LOD:
设置:单个设置Shader.maximumLOD、全局设置Shader.globalMaximumLOD、QualitySettings里面的Maximum LODLevel
原理:小于指定值的shader和subshader才能被使用。
应用:有时候一些显卡虽然支持很多特性,但是效率很低,此时就可以用LOD来进行控制。
内置shader的LOD值:
VertexLit kind of shaders = 100
Decal, Reflective VertexLit = 150
Diffuse = 200
Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
Bumped, Specular = 300
Bumped Specular = 400
Parallax = 500
Parallax Specular = 600
注释:Shader自身的LOD会覆盖全局的LOD。
public Shader targetShader; private void Start () { // 全局的值会被Shader本地址覆盖 Shader.globalMaximumLOD = 300; if (targetShader != null) { targetShader.maximumLOD = 600; } }
RenderQueue:
mtrl.renderQueue = 1000;
shader中使用ZTest Always,可以让被遮住的物体也渲染。
AlphaTest:
固定管线:使用AlphaTest命令
动态管线:使用clip(alpha - cutoff)指令来实现
Alpha检测在ps完成计后,即将写入帧之前,通过和一个固定的数值比较,来决定当前ps的计算结果到底要不要写入帧中。
// inside SubShader Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" } // inside CGPROGRAM in the fragment Shader: clip(textureColor.a - alphaCutoffValue);
AlphaTest抗锯齿:
// inside SubShader Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" } // inside Pass AlphaToMask On
AlphaBlend:
shader渲染的最后一步,决定怎样将当前计算结果写入到帧缓存中。
命令集:
Blend BlendOp AlplaToMask
// inside SubShader Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" } // inside Pass ZWrite Off Blend SrcAlpha OneMinusSrcAlpha
AlphaBlend会有一系列和绘制顺序相关的问题,涉及到的知识点如下:
(1)Unity通过Queue保证所有的不透明物体Geometry都会在半透明物体Transparent之前被渲染,(Queue标签决定了这个对象的渲染队列);
(2)Unity保证所有Transparent队列的物体,按distance(物体的远近,不是像素的)从后往前渲染;
(3)distance的计算方式:使用网格的几何中心点来进行半透明物体的排序。
对于部分遮挡的物体,还是会产生不正确的遮挡效果。因此我们要么分割网格,要么使用Alpha Test或者开启ZWrite来替代。
AlphaTest和AlphaBlend的性能比较:
官方文档在这里:https://docs.unity3d.com/Manual/SL-ShaderPerformance.html
翻译如下:
固定管线的AlphaTest和可编程管线的clip()函数,在不同平台有不同性能表现:
(1)多数平台上,AlphaTest这种整个剔除透明像素的做法能获得一点点性能优势;
(2)在ios和android这样基于PowerVR GUPs的设备上,AlphaTest是非常耗资源的,不要企图使用它来做性能优化,因为它会让游戏更慢(是因为直接丢掉像素,让GPUs的某些优化策略没法执行了)。
所以结论是:手机上尽量使用AlphaBlend而不是AlphaTest。
ColorMask:
ColorMask RGB | A | 0 | any combination of R, G, B, A
ColorMask也是耗费比较大的操作,只在确实需要时使用。
ZWrite/ZTest:
ZWrite On | Off
ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always
关于相机的深度贴图_CameraDepthTexture:
(1)默认材质都自带RenderType的Tag;
(2)自定义sahder只有添加RenderType标签才会将深度写到_CameraDepthTexture。
Offset:
对Z深度的偏移。
可以让像素看起来更靠前或更靠后,当两个面重叠时,可以手动指定谁相对靠前一些,而且不会战胜z-fitting。
Offset只会对ZTest的条件做修正,但是并不会改变最后的Z缓冲。
GrabPass:
抓取当前屏幕当做贴图使用。
Shader "James/VP Shader/GrabPass" { Properties { _MainTex("MainTex", 2D) = "white" {} } SubShader { // 在所有不透明几何体之后自画,这一点很重要 Tags { "Queue" = "Transparent" } GrabPass { "_MyGrab" } Pass { CGPROGRAM #pragma vertex vs #pragma fragment ps #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float3 color : COLOR0; float2 uv : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _MyGrab; v2f vs(appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } float4 ps(v2f i):COLOR { float4 texColor = tex2D(_MainTex, i.uv); float4 grabColor = tex2D(_MyGrab, i.uv); return texColor * grabColor; } ENDCG } } FallBack "Diffuse" }
Fog:
雾效实现的三种方式:
(1)全局雾
RenderSettings.fog = true; RenderSettings.fogColor = Color.red; RenderSettings.fogMode = FogMode.Linear; RenderSettings.fogStartDistance = 0; RenderSettings.fogEndDistance = 10;
(2)Fog指令
Fog{ Mode Linear Color(1, 0, 0) Range 0, 10 }
(3)Shader计算方式
Shader "James/VP Shader/Fog" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _FogColor("FogColor", Color) = (1, 1, 1, 1) _Density("Density", Range(0, 10)) = 1 _NearDistance("NearDistance", Float) = 0 _FarDistance("FarDistance", Float) = 10 } SubShader { Tags { "RenderType"="Opaque" } Fog { Mode Off } Pass { CGPROGRAM #pragma vertex vs #pragma fragment ps #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float3 color : COLOR0; float2 uv : TEXCOORD0; float4 depth : TEXCOORD1; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _FogColor; float _Density; float _NearDistance; float _FarDistance; v2f vs(appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.depth = mul(UNITY_MATRIX_MV, v.vertex); o.depth.z = -o.depth.z; o.depth.w = (_FarDistance - _NearDistance) * o.depth.w; return o; } float4 ps(v2f i):COLOR { float4 texColor = tex2D(_MainTex, i.uv); float fg = 0; if(i.depth.z > _NearDistance && i.depth.z < _FarDistance) { fg = i.depth.z / i.depth.w; } else if(i.depth.z > _FarDistance) { fg = _FarDistance / i.depth.w; } return fg * _Density * _FogColor * texColor; } ENDCG } } FallBack "Diffuse" }
Stencil:
Stencil-Test在Z-Test和Alpha-Test之前,如果模板检测不通过,则像素直接被丢掉而不会执行fragment函数。
Shader "James/VP Shader/Stencil" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _refVal("Stencil Ref Value",int)=0 } SubShader { Tags { "RenderType"="Opaque" } ZTest Always Stencil { Ref [_refVal] Comp GEqual Pass Replace Fail keep ZFail keep } Pass { CGPROGRAM #pragma vertex vs #pragma fragment ps #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float3 color : COLOR0; float2 uv : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vs(appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } float4 ps(v2f i):COLOR { float4 texColor = tex2D(_MainTex, i.uv); return texColor; } ENDCG } } FallBack "Diffuse" }