Unity笔记 Surface Shader
来源:互联网 发布:网络文明传播志愿活动 编辑:程序博客网 时间:2024/05/02 02:59
学习《unity shaders and effects book》的tips。
拿到代码后就可以开始了,看代码比看书快很多。
配套代码csdn下载
Nvidia cg tutorial
预备:
Unity 5 的stand shader
学习这个可以做为一种效果参照,并且熟悉相关概念。
Main Maps
Albedo,diffuse纹理,可以设置tintcolor和一张纹理。
Metallic,设置材质的金属感大小。贴图R通道可以指的metallic。A通道制定smoothness。G、B没有使用。
Specular,和metallic二选一。用于设置反射环境的程度。
Normal Map,法线贴图,可以设置负数。
Height Map,高度贴图。
Occlusion,屏蔽反光区域。
Emission,发光贴图,可以是彩色的,用于模拟显示器。
Detail Mask,用于控制第二贴图。
Secondary Maps
细节题图。
简单例子注解
Shader "CookbookShaders/Chapter1/BasicDiffuse" // 在材质选shader时的路径{ Properties // 在材质中可设置的参数 { _EmissiveColor ("Emissive Color", Color) = (1,1,1,1) // 颜色控制参数,自己颜色 _AmbientColor ("Ambient Color", Color) = (1,1,1,1) // 颜色控制参数,环境颜色 _MySliderValue ("This is a Slider", Range(0,10)) = 2.5 // 颜色控制参数,这里用一个范围slider } SubShader // 一段备选shader代码 { Tags { "RenderType"="Opaque" } // 设置为“不透明体”,这会影响渲染顺序 LOD 200 // 这个值越高对应效果越复杂的shader[手册](http://docs.unity3d.com/Manual/SL-ShaderLOD.html) Cull Back // 这个位置可以设置标识[手册](http://docs.unity3d.com/Manual/SL-CullAndDepth.html) CGPROGRAM // 开始CG代码 #pragma surface surf BasicDiffuse // surface函数是surf 使用自定义光照处理函数LightingBasicDiffuse // 颜色控制参数,这里要定义一套一样的 float4 _EmissiveColor; float4 _AmbientColor; float _MySliderValue; // 自定光照处理,这里注意这个函数在surf后执行,返回一个像素的颜色,s是surf的结果,lightDir是unity帮你算好这个点上的光方向,atten光衰减 inline float4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten) { // 法线和光方向,计算光强度 float difLight = max(0, dot (s.Normal, lightDir)); // 颜色结果变量 float4 col; // 颜色这样算出 col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2); // 透明度直接赋值 col.a = s.Alpha; return col; } // 自定义surf需要的一个像素的信息,需要的如果unity有就加上 struct Input { // 主纹理的uv,其实也没有用到 float2 uv_MainTex; }; // 表明函数,vs之后,ps阶段,LightingBasicDiffuse 之前,IN输入,o输出(成员固定,和IN不同) void surf (Input IN, inout SurfaceOutput o) { // 根据材质里的设置生成一个颜色 float4 c; c = pow((_EmissiveColor + _AmbientColor), _MySliderValue); // 赋值给输出的Albedo成员(diffuse color) o.Albedo = c.rgb; // 透明度给Alpha o.Alpha = c.a; } ENDCG // 结束CG } FallBack "Diffuse" // 所有subshader都失败,执行这个shader}
用到的数据类型
float: high precision floating point. Generally 32 bits, just like float type in regular programming languages.
half: medium precision floating point. Generally 16 bits, with a range of –60000 to +60000 and 3.3 decimal digits of precision.
qualcomm的人建议使用,但是实际应用中不能保证兼容性。
fixed: low precision fixed point. Generally 11 bits, with a range of –2.0 to +2.0 and 1/256th precision.
fixed用于颜色,方向什么的足够了
unity3种shader编写方式:
固定管线(设置一些开关为主)
surface shader(本书主要介绍的)
shader(也不是原生的shader代码,最大灵活度)
unity3种rendering path:
forward(最普通,一个一个的渲染物体然后blend)
deferred(延迟渲染,需要多个rendertaget减少ps重复计算效率高,暂时移动平台支持的不好)
vertex lit(逐顶点光照这个快,相对于逐像素光照)
struct Input成员可制定的输入结构体:
用到再声明。
float3 viewDir - will contain view direction, for computing Parallax effects, rim lighting etc.
float4 with COLOR semantic - will contain interpolated per-vertex color.
float4 screenPos - will contain screen space position for reflection or screenspace effects.
float3 worldPos - will contain world space position.
float3 worldRefl - will contain world reflection vector if surface shader does not write to o.Normal. See Reflect-Diffuse shader for example.
float3 worldNormal - will contain world normal vector if surface shader does not write to o.Normal.
float3 worldRefl; INTERNAL_DATA - will contain world reflection vector if surface shader writes to o.Normal. To get the reflection vector based on per-pixel normal map, use WorldReflectionVector (IN, o.Normal). See Reflect-Bumped shader for example.
float3 worldNormal; INTERNAL_DATA - will contain world normal vector if surface shader writes to o.Normal. To get the normal vector based on per-pixel normal map, use WorldNormalVector (IN, o.Normal).
SurfaceOutput成员固定的输出结构体:
struct SurfaceOutput
{
fixed3 Albedo; // diffuse color
fixed3 Normal; // tangent space normal, if written
fixed3 Emission;
half Specular; // specular power in 0..1 range
fixed Gloss; // specular intensity
fixed Alpha; // alpha for transparencies
};
unity 5
struct SurfaceOutputStandard
{
fixed3 Albedo; // base (diffuse or specular) color
fixed3 Normal; // tangent space normal, if written
half3 Emission;
half Metallic; // 0=non-metal, 1=metal
half Smoothness; // 0=rough, 1=smooth
half Occlusion; // occlusion (default 1)
fixed Alpha; // alpha for transparencies
};
struct SurfaceOutputStandardSpecular
{
fixed3 Albedo; // diffuse color
fixed3 Specular; // specular color
fixed3 Normal; // tangent space normal, if written
half3 Emission;
half Smoothness; // 0=rough, 1=smooth
half Occlusion; // occlusion (default 1)
fixed Alpha; // alpha for transparencies
};
第一章
BasicDiffuse
定义了#pragma surface surf BasicDiffuse
LightingBasicDiffuse 代替了默认的光照。
自定义的三种光照模型方式,选自己需要的:
1)half4 Lighting (SurfaceOutput s, half3 lightDir, half atten);
This is used in forward rendering path for light models that are not view direction dependent (e.g. diffuse).
2)half4 Lighting (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten);
This is used in forward rendering path for light models that are view direction dependent.
3)half4 Lighting_PrePass (SurfaceOutput s, half4 light);
This is used in deferred lighting path.
实验:加入多个灯光,设置Lighting中的Ambient Color(主环境色)都会对这个shader产生影响。
结论:inline float4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten)其中的 lightDir是Unity计算好多个光源后的结果(针对每个像素),这可以直接输出lightDir到最终颜色来验证。
col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
这里使用的s.Albedo是surf的结果。
类似lightDir,_LightColor0.rgb也是多个光源的结果值。加入点光后可验证forwordbase行为(注意调整 render mode)。unity shader中光线是一块要展开学习的内容手册。
这里forword来说2个pass种类:
1)base是1个pixel级别光+4个vertex lit+n个SH。
2)add如果还需要pixel级别的在这个pass处理,每加一个会多一个pass来处理。
atten 指的是衰减attenuation。
执行顺序是先surf 后LightingBasicDiffuse,这两个都是ps阶段(每个像素处理)。
HalfLambertDiffuse
float hLambert = difLight * 0.5 + 0.5; 而已。
BRDFDiffuse
这个shader相当巧妙,效果佳、效率高、好控制。
用一张贴图实现了2灯和3灯布光。
1维采样,2灯
float difLight = dot (s.Normal, lightDir);
float hLambert = difLight * 0.5 + 0.5;
float3 ramp = tex2D(_RampTex, float2(hLambert,hLambert)).rgb;
2维采样,3灯,viewDir的使用。
float difLight = dot (s.Normal, lightDir);
float rimLight = dot(s.Normal, viewDir);
float hLambert = difLight * 0.5 + 0.5;
float3 ramp = tex2D(_RampTex, float2(hLambert, rimLight)).rgb;
第二章
ScrollingUVs
// 先存原始UVfixed2 scrolledUV = IN.uv_MainTex;// _Time是unity built-in的值 http://docs.unity3d.com/Manual/SL-UnityShaderVariables.htmlfixed xScrollValue = _ScrollXSpeed * _Time;fixed yScrollValue = _ScrollYSpeed * _Time;// 做偏移scrolledUV += fixed2(xScrollValue, yScrollValue);// 这里用 _MainTint 来染色half4 c = tex2D (_MainTex, scrolledUV);o.Albedo = c.rgb * _MainTint;o.Alpha = c.a;
AnimatedSprite
利用cs脚本传入一个时间参数
timeValue = Mathf.Ceil(Time.time % 16);
transform.GetComponent().material.SetFloat(“_TimeValue”, timeValue);
需要在Properties里加_TimeValue (“Time Value”, float) = 0.0
TextureBlending
WOW就是这样笔刷地形贴图的方式(贴图本身的alpha也没浪费,用做反光),试想一个tile模型上多种地形交叉,并且还要铺条路。
把各层(草、石头、路面)纹理编辑结果(8bit是0~255级)放在一张贴图的各个Channel里。
但是5.0版本编译这个shader有个问题5张贴图呀,要加#pragma target 4.0才成。手册
此处如何拆分处理需要花时间研究,先mark一下吧。继续看……
NormalMapping
unpacknormal来计算正确的法线。
ProceduralTexture
纹理生成方式在cs脚本中。
PhotoshopLevels
本章花时间理解算法挺好,毕竟是个效果处理的基础。
shader中定义了一个函数来减少代码
float GetPixelLevel(float pixelColor){ float pixelResult; pixelResult = (pixelColor * 255.0); pixelResult = max(0, pixelResult - _inBlack); pixelResult = saturate(pow(pixelResult / (_inWhite - _inBlack), _inGamma)); pixelResult = (pixelResult * (_outWhite - _outBlack) + _outBlack)/255.0; return pixelResult;}
第三章
BlinnPhong
使用unity的光照模型:BlinnPhong或Lambert
#pragma surface surf BlinnPhong
Phong
使用需要视点方向的自定光照模型:
inline fixed4 LightingPhong (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
计算出反光向量:
//Calculate diffuse and the reflection vectorfloat diff = dot(s.Normal, lightDir);float3 reflectionVector = normalize((2.0 * s.Normal * diff) - lightDir);//Calculate the Phong specularfloat spec = pow(max(0,dot(reflectionVector, viewDir)), _SpecPower);float3 finalSpec = _SpecularColor.rgb * spec;//Create final colorfixed4 c;c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * finalSpec);c.a = 1.0;return c;
CustomBlinnPhong
jim blinn带入cg世界的算法,高效且效果好。
半角矢量halfVector。
float3 halfVector = normalize (lightDir + viewDir);float diff = max (0, dot (s.Normal, lightDir));float NdotH = max (0, dot (s.Normal, halfVector));float spec = pow (NdotH, _SpecPower);float4 c;c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * _SpecularColor.rgb * spec) * (atten * 2);c.a = s.Alpha;return c;
SpecularMask
使用R通道当成反光强度,rgb做为颜色
//Set the parameters in the Output Structo.Albedo = c.rgb;o.Specular = specMask.r;o.SpecularColor = specMask.rgb;o.Alpha = c.a;
s.Specular参与运算
float spec = pow(max(0.0f,dot(reflectionVector, viewDir)), _SpecPower) * s.Specular;
MetallicSoft
使用纹理来控制反光,的软反光。
fresnel,菲涅尔反射 简单的讲,就是视线垂直于表面时,反射较弱,而当视线非垂直表面时,夹角越小,反射越明显。如果你看向一个圆球,那圆球中心的反射较弱,靠近边缘较强。
Anisotropic
拉丝钢板效果。
需要一张拉丝的法线贴图。
这里surfaceoutput是这样的:
struct SurfaceAnisoOutput{ fixed3 Albedo; fixed3 Normal; fixed3 Emission; fixed3 AnisoDirection; half Specular; fixed Gloss; fixed Alpha;};
经过法线贴图的修改和halfVector做点积,算出夹角。
half HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180.0f)));
第四章
GenerateStaticCubemap
新建一个cubemap 把readable勾选。
指的一个位置。
cs脚本,放在Editor文件夹里。
using UnityEngine;using UnityEditor;using System.Collections;public class GenerateStaticCubemap : ScriptableWizard { public Camera renderPosition; // 这个可以更换成Camera,生成cubemap时可以调整如:背景色、FOV等 public Cubemap cubemap; void OnWizardUpdate() { // 制定public参数时会被调用,做有效性验证,设置ScriptableWizard提供的isValid变量 helpString = "Select transform to render" + " from and cubemap to render into"; if (renderPosition != null && cubemap != null) { isValid = true; } else { isValid = false; } } void OnWizardCreate() { renderPosition.GetComponent<Camera>().RenderToCubemap(cubemap); } [MenuItem("CookBook/Render Cubemap")] static void RenderCubemap() { ScriptableWizard.DisplayWizard("Render CubeMap", typeof(GenerateStaticCubemap), "Render!"); }}
使用 IN.worldRefl 和 texCUBE 采样cubemap赋值给Emission。
o.Emission = texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflAmount;
MaskedReflection
添加纹理做mask
half4 c = tex2D (_MainTex, IN.uv_MainTex);float3 reflection = texCUBE(_Cubemap, IN.worldRefl).rgb;float4 reflMask = tex2D(_ReflMask, IN.uv_MainTex);o.Albedo = c.rgb * _MainTint;o.Emission = (reflection * reflMask.r) * _ReflAmount;o.Alpha = c.a;
NormalMappedReflection
法线参与反射计算
float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;o.Normal = normals;
FresnelReflection
菲涅尔反射
half4 c = tex2D (_MainTex, IN.uv_MainTex);float rim = 1-saturate(dot(o.Normal, normalize(IN.viewDir)));rim = pow(rim, _RimPower);o.Albedo = c.rgb * _MainTint.rgb;o.Emission = (texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflectionAmount) * rim;o.Specular = _SpecPower;o.Gloss = 1.0;o.Alpha = c.a;
动态cubemap
就是根据距离选择相应的cubemap(reflection probe)。
NFSnl实时环境使用了SEM(Spherical Environment Map)不是cubemap,在手机上运行效率良好。地面和车体都有使用。有空可以研究这个方案。
[ExecuteInEditMode]这个可以在编辑模式运行,是个不错的调试方法。
第五章
第六章
第七章
第八章
第九章
第十章
灰度
cs脚本,要添加成摄像机组件,指定shader,后面用的都是类似脚本只是参数不同。
2个用到的api:
http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnRenderImage.html
RenderTexture sourceTexture
这个可以通过设置camera的rect来达到控制视口的目的。
RenderTexture destTexture
这个就是camera的render target。
http://docs.unity3d.com/ScriptReference/Graphics.Blit.html
[ExecuteInEditMode] 这个添加后就可以不用运行在Game窗口中看到效果。
using UnityEngine;using System.Collections;[ExecuteInEditMode]public class TestRenderImageG : MonoBehaviour { #region Variables public Shader curShader; public float grayScaleAmount = 1.0f; private Material curMaterial; #endregion #region Properties Material material{ get{ if (curMaterial == null) { curMaterial = new Material(curShader); curMaterial.hideFlags = HideFlags.HideAndDontSave; } return curMaterial; } } #endregion void Start () { if (!SystemInfo.supportsImageEffects) { enabled = false; return; } if (!curShader && !curShader.isSupported) { enabled = false; } } void Update () { grayScaleAmount = Mathf.Clamp( grayScaleAmount, 0.0f, 1.0f ); } void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture) { if (curShader != null) { material.SetFloat("_LuminosityAmount", grayScaleAmount); Graphics.Blit(sourceTexture, destTexture, material); } else { Graphics.Blit(sourceTexture, destTexture); } } void OnDisable() { if (curMaterial) { DestroyImmediate( curMaterial ); } }}
添加后需要指定一个cg shader,这里没有使用surface。
常见方式通过参数来调整效果百分比。
half4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount);
Shader "Custom/ImageEffectG" { Properties{ _MainTex("Main Texture",2D) = "white"{} _LuminosityAmount ("GrayScale Amount" , Range(0.0,1)) = 1.0 } SubShader{ Pass{ CGPROGRAM #pragma vertex vert_img #pragma fragment frag // 指定一个叫frag的ps #pragma fragmentoption ARB_precision_hint_fastest // 计算数值的精确度,不用太在意 #include "UnityCG.cginc" sampler2D _MainTex; fixed _LuminosityAmount; half4 frag(v2f_img i) : COLOR { half4 renderTex = tex2D(_MainTex, i.uv); float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b; half4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount); return finalColor; } ENDCG } } Fallback "Diffuse"}
SceneDepth_Shader
深度,不知是不是unity版本问题这里采样y方向反了……
这样改了一下y方向采样:
float d = UNITY_SAMPLE_DEPTH( tex2D(_CameraDepthTexture, float2( i.uv.x, 1.0 - i.uv.y )) );
BSC_Effect
调整Brightness(亮度), saturation(饱和), contrast(对比)。
有个函数调用的例子。
BlendMode_Effect
3种混合模式:
fixed4 blendedMultiply = renderTex * blendTex;fixed4 blendedAdd = renderTex + blendTex;fixed4 blendedScreen = (1.0 - ((1.0 - renderTex) * (1.0 - blendTex)));
Overlay_Effect
根据条件判断采用的混合模式:
fixed OverlayBlendMode(fixed basePixel, fixed blendPixel){ if(basePixel < 0.5) { return (2.0 * basePixel * blendPixel); } else { return (1.0 - 2.0 * (1.0 - basePixel) * (1.0 - blendPixel)); }}
第十一章
2个比较复杂的ps效果,很好的参考。
OldFilmEffectShader
UV动画中使用,_SinTime 和 _RandomValue。
NightVisionEffectShader
这里有个透镜变形的算法。
- Unity笔记 Surface Shader
- unity surface shader 1
- unity surface shader植物
- Unity surface shader 2
- Unity Surface Shader 示例分析
- 【Unity Shaders】Surface Shader 概述
- Unity Shader 表面着色器(Surface Shader)
- Unity Shader 学习笔记(29) 表面着色器(Surface Shader)
- 【Unity Shader】剖析Unity Surface Shader背后机制(一)
- 【Unity Shader】剖析Unity Surface Shader背后机制(二)
- Unity Shader——Writing Surface Shaders
- 【Unity】Surface Shader的Input输入结构
- Unity Shader——Writing Surface Shaders
- 【Unity Shaders】Shader学习资源和Surface Shader概述
- 【Unity Shaders】Shader学习资源和Surface Shader概述
- unity Shader学习资源和Surface Shader概述
- Unity Shader(4)——surface shader(三)
- Surface Shader
- 数据管理(选择 删除 )
- 解决Masonry 中equalTo和mas_equalTo 乱用的问题
- Android自定义ViewPager的过渡动画
- 云栖大会马云演讲笔记
- 泛谈移动互联时代的交互设计师
- Unity笔记 Surface Shader
- GMM-HMM语音识别模型 原理篇
- 时间戳转换时间
- C学习提高篇(1):数据类型本质及变量本质分析
- 多线程的那点儿事(之原子锁)
- NDK调试
- 扩展欧几里得 解方程小记
- opengl shader
- Linux du命令查看文件夹和文件大小