@ -0,0 +1,566 @@ | 
				
			|||||||
 | 
					# 屏幕后期处理效果 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在渲染完整个场景之后,得到的屏幕图像进行了一系列操作,最终实现各种屏幕特效,如Bloom,SSAO等等。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					要实现屏幕后期处理的基础是,必须得到渲染后的屏幕图像,即抓取屏幕,而Unity为我们提供了这样一个方便的接口---OnRenderImage函数。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 写在前面 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					简单介绍几个常用名词。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 0.1 UV | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					U和V分别是图片在显示器水平、垂直方向上的坐标,取值范围是0~1。通常是从左往右,从下往上从0开始依次递增。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1.基础类 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在进行屏幕后期处理之前,我们需要检查一系列条件是否满足,例如当前平台是否支持渲染纹理跟屏幕特效。是否支持当前使用的shader等。为此,我们创建了一个用于屏幕后期处理效果的基类。在实现各种屏幕特效时,我们只需继承基础类。在实现派生类中不同操作即可。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					using UnityEngine; | 
				
			||||||
 | 
					using System.Collections; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ExecuteInEditMode] | 
				
			||||||
 | 
					[RequireComponent (typeof(Camera))] | 
				
			||||||
 | 
					public class PostEffectsBase : MonoBehaviour { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 开始检查 | 
				
			||||||
 | 
					    protected void CheckResources() { | 
				
			||||||
 | 
					        bool isSupported = CheckSupport(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isSupported == false) { | 
				
			||||||
 | 
					            NotSupported(); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 在检查是否支持屏幕后期shader的时候调用 | 
				
			||||||
 | 
					    protected bool CheckSupport() { | 
				
			||||||
 | 
					        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) { | 
				
			||||||
 | 
					            Debug.LogWarning("This platform does not support image effects or render textures."); | 
				
			||||||
 | 
					            return false; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 在不支持屏幕后期shader的时候调用。 | 
				
			||||||
 | 
					    protected void NotSupported() { | 
				
			||||||
 | 
					        enabled = false; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected void Start() { | 
				
			||||||
 | 
					        CheckResources(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 在需要通过该屏幕后期shader创建相应材质的时候调用。 | 
				
			||||||
 | 
					    protected Material CheckShaderAndCreateMaterial(Shader shader, Material material) { | 
				
			||||||
 | 
					        if (shader == null) { | 
				
			||||||
 | 
					            return null; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (shader.isSupported && material && material.shader == shader) | 
				
			||||||
 | 
					            return material; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!shader.isSupported) { | 
				
			||||||
 | 
					            return null; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        else { | 
				
			||||||
 | 
					            material = new Material(shader); | 
				
			||||||
 | 
					            material.hideFlags = HideFlags.DontSave; | 
				
			||||||
 | 
					            if (material) | 
				
			||||||
 | 
					                return material; | 
				
			||||||
 | 
					            else  | 
				
			||||||
 | 
					                return null; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 基础类使用案例(继承PostEffectBase) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					using System.Collections; | 
				
			||||||
 | 
					using System.Collections.Generic; | 
				
			||||||
 | 
					using UnityEngine; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ImageEffectGeneral : PostEffectsBase{ | 
				
			||||||
 | 
					    public Shader scannerShader; | 
				
			||||||
 | 
					    private Material scannerMaterial; | 
				
			||||||
 | 
					    public Material material | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        get | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            // 检查是否生成对应材质 | 
				
			||||||
 | 
					            scannerMaterial = CheckShaderAndCreateMaterial(scannerShader, scannerMaterial); | 
				
			||||||
 | 
					            return scannerMaterial; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    //定义相关数据调整 | 
				
			||||||
 | 
					    public string dataTags = ""; | 
				
			||||||
 | 
					    public float dataScale = 1.0f; | 
				
			||||||
 | 
					    public new void Start() | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        //如果需要提前规定Camera获取深度纹理或者法线纹理,需要提前声明 | 
				
			||||||
 | 
					        //GetComponent<Camera>().depthTextureMode = DepthTextureMode.DepthNormals; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void OnRenderImage(RenderTexture src, RenderTexture dest) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        //GetComponent<Camera>().depthTextureMode = DepthTextureMode.DepthNormals; | 
				
			||||||
 | 
					        if (material != null) | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            //需要传入的数据,需要在Shader中定义好对应变量名称,作为传入依据。 | 
				
			||||||
 | 
					            material.SetFloat(dataTags, dataScale); | 
				
			||||||
 | 
					            Graphics.Blit(src, dest, material); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        else | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            Graphics.Blit(src, dest); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.使用渲染纹理 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在Unity中,获取深度纹理是非常简单的,直接在脚本中设置摄像机的depthTextureMode,就可以获取对应的纹理数据。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					深度纹理获取 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth; | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					法线纹理+深度纹理获取: | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					GetComponent<Camera>().depthTextureMode = DepthTextureMode.DepthNormals; | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 深度纹理采样 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当在Shader中访问到深度纹理 _CameraDepthTexture 后,我们就可以使用当前像素的纹理坐标对它进行采样。绝大多数情况下,我们直接使用tex2D函数采样即可,但在某些平台(例如PS3或者PSP)上,我们需要一些特殊处理。Unity为我们提供了一个统一的宏,SAMPLE_Depth_Texture,用来处理这些由于平台差异造成的问题。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 法线纹理采样 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					用以下语句进行的法线采样,是范围在-1~1之间的水平&垂直法线值,如果需要展示成法线贴图,需要手动对normal进行归一化处理 normal = 0.5*normal+0.5 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					fixed3 normal = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture,i.uv)); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#  | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 屏幕后期处理效果实例 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1.uv应用:扭曲 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					通过重新计算uv,采用黑白图来对uv进行重新赋值,可以产生扭曲的效果。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					Shader "Hidden/ImageDistort" | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    Properties | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        _MainTex ("Texture", 2D) = "white" {} | 
				
			||||||
 | 
					        _DistortTex ("Distort Texture", 2D) = "white" {} | 
				
			||||||
 | 
					        _DistortScale ("Distort Scale",Range(0,1)) = 1.0  | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    SubShader | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        // No culling or depth | 
				
			||||||
 | 
					        Cull Off ZWrite Off ZTest Always | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Pass | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            CGPROGRAM | 
				
			||||||
 | 
					            #pragma vertex vert | 
				
			||||||
 | 
					            #pragma fragment frag | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #include "UnityCG.cginc" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sampler2D _MainTex; | 
				
			||||||
 | 
					            sampler2D _DistortTex; | 
				
			||||||
 | 
					            float _DistortScale; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            struct appdata | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                float4 vertex : POSITION; | 
				
			||||||
 | 
					                float2 uv : TEXCOORD0; | 
				
			||||||
 | 
					            }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            struct v2f | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                float2 uv : TEXCOORD0; | 
				
			||||||
 | 
					                float4 vertex : SV_POSITION; | 
				
			||||||
 | 
					            }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            v2f vert (appdata v) | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                v2f o; | 
				
			||||||
 | 
					                o.vertex = UnityObjectToClipPos(v.vertex); | 
				
			||||||
 | 
					                o.uv = v.uv; | 
				
			||||||
 | 
					                return o; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fixed4 frag (v2f i) : SV_Target | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                //i.uv = abs(0.5-i.uv); | 
				
			||||||
 | 
					                fixed4 noise = tex2D(_DistortTex,i.uv); | 
				
			||||||
 | 
					                i.uv = i.uv + (0.5-noise.r) * _DistortScale*0.1; | 
				
			||||||
 | 
					                fixed4 col = tex2D(_MainTex, i.uv); | 
				
			||||||
 | 
					                // just invert the colors | 
				
			||||||
 | 
					                //col.rgb = 1 - col.rgb; | 
				
			||||||
 | 
					                return col; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            ENDCG | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用时,可以参考上述中的,基础类使用案例,编写对应的cs脚本并挂在摄像机上,通过调整相关参数来观看对应效果 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.深度纹理应用:扫描效果探究 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					深度图的每一个像素值表示场景中某点与摄像机的距离。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					是指将从图像采集器到场景中各点的距离(深度)作为像素值的图像,它直接反映了景物可见表面的几何形状。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shader中,深度图的获取可以通过以下代码进行 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					float linearDepth = Linear01Depth(depth); | 
				
			||||||
 | 
					fixed4 col = fixed4(linearDepth,linearDepth,linearDepth,1); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当通过纹理采样SAMPLE_DEPTH_TEXTURE之后,得到的深度值往往是非线性的。然而,我们的计算过程中通常是需要线性的深度值,也就是说,我们需要把投影后的深度值变换到线性空间下。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					最终结果如下,上图为原始场景,下图为场景中提取的深度图(通过Linear01Depth解码) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					0表示该点和摄像机处于同一位置,1表示该点位于视锥体的远裁剪平面上(摄像机Near=0.3 Far=50) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LinearEyeDepth负责把深度纹理的采样结果转换到视角空间下的深度值 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LinearEyeDepth解码,此时的摄像机远裁剪平面与近裁剪平面并不会对结果产生影响,通过调节参数_DepthParam,看对应的变化区间(下图为_DepthParam为10的样子,即黑的部分是离镜头10m以内的,白色部分是离镜头11m以外的,模糊的部分为距离10-11m之间的值) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					float linearDepth = LinearEyeDepth(depth); | 
				
			||||||
 | 
					float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用floor函数,对上述的值进行取整,并对采样值归一化,可以得到比较尖锐化的边缘,此时深度在11m范围内的部分会全部变成黑色。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					float linearDepth = LinearEyeDepth(depth); | 
				
			||||||
 | 
					float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
					diff = saturate(floor(diff)); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					通过负数取值归一化,可对采样值进行反色,让黑的部分变白,白的部分变黑。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					float linearDepth = LinearEyeDepth(depth); | 
				
			||||||
 | 
					float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
					diff = saturate(-diff); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					上述操作中,如果不进行归一化(取值范围限制在0-1之间)的话,黑的部分可能会产生负数,白的部分可能会超过1,最终可能计算不出正确结果。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					将上述两张图按加算合起来,得到一个按深度扫描的效果雏形 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					float linearDepth = LinearEyeDepth(depth); | 
				
			||||||
 | 
					float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
					diff = saturate(floor(diff))+saturate(-diff); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					得到这部分后,因为归一化前面已经做过了,我们仅需要对上述结果进行反色处理(1-diff),再混合上原背景(对原图像进行插值处理,此时我们用到前面所提到的插值函数lerp),就可以看到对应的扫描效果了。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					fixed4 mainTex = tex2D(_MainTex, i.uv); | 
				
			||||||
 | 
					float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					float linearDepth = LinearEyeDepth(depth.r); | 
				
			||||||
 | 
					fixed4 col = fixed4(linearDepth,linearDepth,linearDepth,1); | 
				
			||||||
 | 
					float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
					fixed4 border = 1-(saturate(floor(diff))+saturate(-diff*0.5)); | 
				
			||||||
 | 
					fixed4 final = lerp(mainTex,border*_DepthColor,border);  | 
				
			||||||
 | 
					return final; | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					下面提供完整代码 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ExampleScannerImage.shader | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					Shader "Hidden/ExampleScannerImage" | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    Properties | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        _MainTex ("Texture", 2D) = "white" {} | 
				
			||||||
 | 
					        _DepthParam ("DepthParam",Float) = 1.0 | 
				
			||||||
 | 
					        _DepthColor("DepthColor",Color) = (1,1,1,1) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    SubShader | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        // No culling or depth | 
				
			||||||
 | 
					        Cull Off ZWrite Off ZTest Always | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Pass | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            CGPROGRAM | 
				
			||||||
 | 
					            #pragma vertex vert | 
				
			||||||
 | 
					            #pragma fragment frag | 
				
			||||||
 | 
					            #include "UnityCG.cginc" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sampler2D _MainTex; | 
				
			||||||
 | 
					            sampler2D _CameraDepthTexture; | 
				
			||||||
 | 
					            float _DepthParam; | 
				
			||||||
 | 
					            fixed4 _DepthColor; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            struct appdata | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                float4 vertex : POSITION; | 
				
			||||||
 | 
					                float2 uv : TEXCOORD0; | 
				
			||||||
 | 
					            }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            struct v2f | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                float2 uv : TEXCOORD0; | 
				
			||||||
 | 
					                float4 vertex : SV_POSITION; | 
				
			||||||
 | 
					            }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            v2f vert (appdata v) | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                v2f o; | 
				
			||||||
 | 
					                o.vertex = UnityObjectToClipPos(v.vertex); | 
				
			||||||
 | 
					                o.uv = v.uv; | 
				
			||||||
 | 
					                return o; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fixed4 frag (v2f i) : SV_Target | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                fixed4 mainTex = tex2D(_MainTex, i.uv); | 
				
			||||||
 | 
					                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
					                float linearDepth = LinearEyeDepth(depth.r); | 
				
			||||||
 | 
					                float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
					                fixed4 border = 1-(saturate(floor(diff))+saturate(-diff*0.5)); | 
				
			||||||
 | 
					                fixed4 final = lerp(mainTex,border*_DepthColor,border);  | 
				
			||||||
 | 
					                return final; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            ENDCG | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PostEffects.cs(参考本篇开头) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ImageScannerEffect.cs | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					using System.Collections; | 
				
			||||||
 | 
					using System.Collections.Generic; | 
				
			||||||
 | 
					using UnityEngine; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ImageScannerEffect : PostEffectsBase | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    public Shader scannerShader; | 
				
			||||||
 | 
					    private Material scannerMaterial; | 
				
			||||||
 | 
					    public Material material | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        get | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            // 检查是否生成对应材质 | 
				
			||||||
 | 
					            scannerMaterial = CheckShaderAndCreateMaterial(scannerShader, scannerMaterial); | 
				
			||||||
 | 
					            return scannerMaterial; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    //定义相关数据调整 | 
				
			||||||
 | 
					    public float dataScale = 1.0f; | 
				
			||||||
 | 
					    public Color dataColor = Color.white; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void OnRenderImage(RenderTexture src, RenderTexture dest) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        //GetComponent<Camera>().depthTextureMode = DepthTextureMode.DepthNormals; | 
				
			||||||
 | 
					        if (material != null) | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            material.SetFloat("_DepthParam", dataScale); | 
				
			||||||
 | 
					            material.SetColor("_DepthColor", dataColor); | 
				
			||||||
 | 
					            Graphics.Blit(src, dest, material); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        else | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            Graphics.Blit(src, dest); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用时,将ImageScannerEffect.cs拖拽至主摄像机中,并且把ExampleScannerImage.shader 这个文件拖至Scanner Shader选项卡中去。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					录制动画,调节脚本中DataScale选项依次增大,完成相关扫描特效的制作。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					可以根据自己喜好,调整相关颜色等操作。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					添加图片遮罩,根据法线纹理生成网格纹理等等我们后续会接着讲。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.纹理附加:扫描效果探究(续) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在上图中,我们由于为对插值处理进行相关优化,所以在尾部会出现一些黑色的部分,这些黑色的部分是因为原本的图像是呈现黑色的。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					这次我们使用一张附加纹理,使得扫描效果更具科技感一些 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					这次是我们使用的附加纹理原图 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在使用上述图片之前,我们需要了解uv转换函数TRANSFORM_TEX | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TRANSFORM_TEX方法比较简单,就是将模型顶点的uv和Tiling、Offset两个变量进行运算,计算出实际显示用的定点uv。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果对_MaskTex这个纹理进行uv转换,必须声明变量_MaskTex_ST(float4类型) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					实际调整的时候,_MaskTex_ST.xy代表Tilling(缩放程度),_MaskTex_ST.zw代表Offset(偏移程度) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					我们在声明变量的时候,沿用_MaskTex的同时下方添加一个ST的声明即可 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					sampler2D _MaskTex; | 
				
			||||||
 | 
					float4 _MaskTex_ST; | 
				
			||||||
 | 
					float _MaskTexTillY; | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					片元着色器 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					_MaskTex_ST.y = _MaskTexTillY; | 
				
			||||||
 | 
					i.uv = TRANSFORM_TEX(i.uv, _MaskTex); | 
				
			||||||
 | 
					fixed4 maskTex = tex2D(_MaskTex,i.uv); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在附加纹理时,可以通过两种方式进行,一种是附加法,一种是累乘法 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					我们这里使用了带颜色的附加法进行(因为包含了黑色,原本是黑色的部分就不会变化) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					同样的,我们在原本的基础上使用了_DepthColor.a 作为底图的影响程度,这样可以淡化尾部的黑色部分。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```cpp | 
				
			||||||
 | 
					fixed4 final = lerp(mainTex,saturate(border*_DepthColor+mainTex*_DepthColor.a+maskTex*_DepthColor),saturate(border)); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					改写完shader后,在cs脚本中添加以下内容即可 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					public Texture dataTex; | 
				
			||||||
 | 
					public float tillY; | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OnRenderImage函数中 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp | 
				
			||||||
 | 
					material.SetTexture("_MaskTex", dataTex); | 
				
			||||||
 | 
					material.SetFloat("_MaskTexTillY", tillY); | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shader完整代码 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c | 
				
			||||||
 | 
					Shader "Hidden/ExampleScannerImage" | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Properties | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							_MainTex ("Texture", 2D) = "white" {} | 
				
			||||||
 | 
							_MaskTex("Mask Texture", 2D) = "white" {} | 
				
			||||||
 | 
							_MaskTexTillY("Till Y",Float) = 1.0 | 
				
			||||||
 | 
							_DepthParam ("DepthParam",Float) = 1.0 | 
				
			||||||
 | 
							_DepthColor("DepthColor",Color) = (1,1,1,1) | 
				
			||||||
 | 
							_DepthLength ("DepthLength",Float) = 1.0 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						SubShader | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							// No culling or depth | 
				
			||||||
 | 
							Cull Off ZWrite Off ZTest Always | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Pass | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CGPROGRAM | 
				
			||||||
 | 
								#pragma vertex vert | 
				
			||||||
 | 
								#pragma fragment frag | 
				
			||||||
 | 
								#include "UnityCG.cginc" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sampler2D _MainTex; | 
				
			||||||
 | 
								sampler2D _CameraDepthTexture; | 
				
			||||||
 | 
								sampler2D _MaskTex; | 
				
			||||||
 | 
								float4 _MaskTex_ST; | 
				
			||||||
 | 
								float _MaskTexTillY; | 
				
			||||||
 | 
								float _DepthParam; | 
				
			||||||
 | 
								fixed4 _DepthColor; | 
				
			||||||
 | 
								float _DepthLength; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct appdata | 
				
			||||||
 | 
								{ | 
				
			||||||
 | 
									float4 vertex : POSITION; | 
				
			||||||
 | 
									float2 uv : TEXCOORD0; | 
				
			||||||
 | 
								}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct v2f | 
				
			||||||
 | 
								{ | 
				
			||||||
 | 
									float2 uv : TEXCOORD0; | 
				
			||||||
 | 
									float4 vertex : SV_POSITION; | 
				
			||||||
 | 
								}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								v2f vert (appdata v) | 
				
			||||||
 | 
								{ | 
				
			||||||
 | 
									v2f o; | 
				
			||||||
 | 
									o.vertex = UnityObjectToClipPos(v.vertex); | 
				
			||||||
 | 
									o.uv = v.uv; | 
				
			||||||
 | 
									return o; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								fixed4 frag (v2f i) : SV_Target | 
				
			||||||
 | 
								{ | 
				
			||||||
 | 
									fixed4 mainTex = tex2D(_MainTex, i.uv); | 
				
			||||||
 | 
									float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv); | 
				
			||||||
 | 
									float linearDepth = LinearEyeDepth(depth.r); | 
				
			||||||
 | 
									float diff = linearDepth-_DepthParam; | 
				
			||||||
 | 
									fixed4 border = 1-(saturate(floor(diff))+saturate(-diff*_DepthLength)); | 
				
			||||||
 | 
									 | 
				
			||||||
 | 
									_MaskTex_ST.y = _MaskTexTillY; | 
				
			||||||
 | 
									i.uv = TRANSFORM_TEX(i.uv, _MaskTex); | 
				
			||||||
 | 
									fixed4 maskTex = tex2D(_MaskTex,i.uv); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									fixed4 final = lerp(mainTex,saturate(border*_DepthColor+mainTex*_DepthColor.a+maskTex*_DepthColor),saturate(border)); | 
				
			||||||
 | 
									return final;  | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								ENDCG | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					具体效果截图 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					此时,我们的扫描效果就已经比上一个阶段高出一个档次了 | 
				
			||||||
@ -0,0 +1,532 @@ | 
				
			|||||||
 | 
					# 前言 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					本编程指南仅尽可能的列出编写一个shader的参考 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#  | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# shader编写结构 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1.定义Properties(方便在创建材质的时候可以传入贴图等数据) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.编写SubShader主题 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.1【Tags】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.2【RenderSetUp】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.2.1【LOD】渲染深度(详情参考Unity LOD 远景渲染部分) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.3【GrabPass】【UsePass】【Pass】【Pass】(第二个或者其他) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----------------------案例Pass-------------------- | 
				
			||||||
 | 
					【RenderSetUp】 | 
				
			||||||
 | 
					CGPROGRAM | 
				
			||||||
 | 
					//编译顶点着色器 | 
				
			||||||
 | 
					#pragma vertex vert | 
				
			||||||
 | 
					//编译片元着色器 | 
				
			||||||
 | 
					#pragma fragment frag | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3.1 其他引用以及其它编译指令 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3.2 声明参数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3.3 设置应用数据->顶点着色器结构体a2v,appdata(a2v为app to vert简写) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3.4 设置顶点->片源着色器结构体v2f(v2f为vert to fragment简写) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3.5 编写顶点着色器渲染方法 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v2f vert (a2v v){ | 
				
			||||||
 | 
					    v2f o; | 
				
			||||||
 | 
					    //着色器内容 | 
				
			||||||
 | 
					    return o; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3.5 编写片源着色器渲染方法 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fixed4 frag (v2f i) : SV_Target{ | 
				
			||||||
 | 
					    fixed4 tex = ...; | 
				
			||||||
 | 
					    //着色器内容 | 
				
			||||||
 | 
					    return tex; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					ENDCG | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.设置Fallback,如果显卡无法运行上面的SubShader,则执行FallBack预设进行渲染 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 1.Properties(参考书籍P30) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 传入数据常用类型 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Int | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Int("Int",Int)=2 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Float | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Float("Float",Float)=1.0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Range | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Range("Range",Range(0.0,5.0))=1.0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Color | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Color("Color",Color)=(1,1,1,1) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Vector | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Vector("Vector",Vector)=(1,1,1,1) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2D | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_MainTex ("Texture", 2D) = "white" {} | 
				
			||||||
 | 
					ps:内置纹理名称包含white、black、gray、bump等等 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Cube | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Cubemap ("Environment Cubemap", Cube) = "_Skybox" {} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3D | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_3D ("3D", 3D) = "black" {} | 
				
			||||||
 | 
					-------------------------------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 2.Tags(参考网站:https://gameinstitute.qq.com/community/detail/121997) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 渲染类型声明(包含渲染顺序) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tags的书写方法为键值对,可多可少,不需要全部声明,未声明时按默认值 | 
				
			||||||
 | 
					Tags { "RenderType"="Opaque" "Queue"="Transparent" } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 2.1(SubShader)Tags | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:Queue | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					渲染顺序,括号内为优先度,值越小越先被渲染 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## value | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Background(1000) | 
				
			||||||
 | 
					Geometry(2000)【默认】 | 
				
			||||||
 | 
					AlphaTest(2450) | 
				
			||||||
 | 
					Transparent(3000) | 
				
			||||||
 | 
					Overlay(4000) | 
				
			||||||
 | 
					可以自定义值例如"Queue"="3100" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:RenderType | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					渲染类型 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## value | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Opaque-----------------不透明(法线、自发光、反射、地形Shader) | 
				
			||||||
 | 
					Transparent------------半透明(透明、粒子、字体、地形添加通道Shader) | 
				
			||||||
 | 
					TransparentCutout------遮罩透明(透明裁切、双通道植物Shader) | 
				
			||||||
 | 
					Background-------------天空盒Shader | 
				
			||||||
 | 
					Overlay----------------GUI纹理、光晕、闪光Shader | 
				
			||||||
 | 
					TreeOpaque-------------地形引擎——树皮 | 
				
			||||||
 | 
					TreeTransparentCutout--地形引擎——树叶 | 
				
			||||||
 | 
					TreeBillboard----------地形引擎——公告牌(始终面向摄像机)式树木 | 
				
			||||||
 | 
					Grass------------------地形引擎——草 | 
				
			||||||
 | 
					GrassBillboard---------地形引擎——公告牌(始终面向摄像机)式草 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:DisableBatching | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					是否禁用Batch(打包、合并) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## value | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					True-------------------禁用 | 
				
			||||||
 | 
					False------------------不禁用(默认) | 
				
			||||||
 | 
					LODFading--------------当LOD fade开启的时候禁用,一般用在树木上面 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:ForceNoShadowCasting | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					是否强制不投射阴影,当这个值为True的时候,使用这个Shader的对象便不会投射阴影。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:IgnoreProjector | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					无视投影器,当这个值为True的时候,对象便不受投射器影响。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:CanUseSpriteAtlas | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					可使用精灵集,当这个值为False的时候,不能使用精灵集。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:PreviewType | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					材质的预览形式,默认显示为球体,可以使用Plane(2D平面)或Skybox(天空盒) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 2.2(Pass)Tags | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:LightMode | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					光照模式 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## value | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Always------------------总是渲染,不使用光照 | 
				
			||||||
 | 
					ForwardBase-------------用于前向渲染,使用环境光、主平行光、顶点/SH(球谐函数)光照以及光照贴图 | 
				
			||||||
 | 
					ForwardAdd--------------用于前向渲染,额外使用每像素光,每个光照一个通道 | 
				
			||||||
 | 
					Deferred----------------用于延迟着色,渲染G-Buffer | 
				
			||||||
 | 
					ShadowCaster------------渲染对象的深度到阴影贴图或者深度纹理 | 
				
			||||||
 | 
					PrepassBase-------------用于(旧版)延迟光照,渲染法线和高光指数 | 
				
			||||||
 | 
					PrepassFinal------------用于(旧版)延迟光照,合并贴图、光照和自发光来渲染最终色彩 | 
				
			||||||
 | 
					Vertex------------------当对象不受光照贴图影响的时候,用来渲染(旧版)顶点发光。使用所有的顶点光照 | 
				
			||||||
 | 
					VertexLMRGBM------------当对象接受光照贴图影响的时候,用来渲染(旧版)顶点发光。适用于使用RGBM编码光照贴图的平台(PC&主机) | 
				
			||||||
 | 
					VertexLM----------------当对象接受光照贴图影响的时候,用来渲染(旧版)顶点发光。适用于使用double-LDR编码光照贴图的平台(移动平台) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:PassFlags | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					标志渲染管线如何传递数据给通道 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## value | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OnlyDirectional---------只有主平行光、环境光和光照探测器的数据会传递给通道。仅用于LightMode为ForwardBase | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## key:RequireOptions | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					标志通道至于在某些外部条件满足时才会被渲染 | 
				
			||||||
 | 
					SoftVegetation----------当Quality Setting中的Soft Vegetation选项被开启时,才会渲染通道 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 3.RenderSetUp(以下写在CGPROGRAM之前)(参考书籍P31) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.1 Cull | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cull Back | Front | Off  | 
				
			||||||
 | 
					设置剔除模式:剔除背面/正面/关闭剔除 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.2 ZTest | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ZTest Less Greater | LEqual | GEqual | Equal | NotEqual | Always | 
				
			||||||
 | 
					设置深度测试时使用的函数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.3 ZWrite | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ZWrite On | Off | 
				
			||||||
 | 
					开启/关闭深度写入 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.4 Blend | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BlendOp (Op) | 
				
			||||||
 | 
					设置混合操作 | 
				
			||||||
 | 
					Blend (SrcFactor) (DstFactor) | 
				
			||||||
 | 
					Blend (SrcFactor) (DstFactor),(SrcFactorA) (DstFactorA) | 
				
			||||||
 | 
					开启并设置混合模式(透明材质用) | 
				
			||||||
 | 
					例如:Blend SrcAlpha OneMinusSrcAlpha | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					其中SrcFactor为源颜色乘以的混合因子 | 
				
			||||||
 | 
					DstFactor为目标颜色乘以的混合因子 | 
				
			||||||
 | 
					两者相加存入颜色缓冲区 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Blend混合操作表(参考书籍P174) | 
				
			||||||
 | 
					----------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Add         |     源颜色和目标颜色相加 | 
				
			||||||
 | 
					Sub         |     源颜色减去目标颜色 | 
				
			||||||
 | 
					RevSub      |     目标颜色减去源颜色 | 
				
			||||||
 | 
					Min         |     使用目标颜色跟源颜色中较小的值 | 
				
			||||||
 | 
					Max         |     使用源颜色跟目标颜色中较大的值 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Blend混合因子表(参考书籍P174) | 
				
			||||||
 | 
					----------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					One              |     1 | 
				
			||||||
 | 
					Zero             |     0 | 
				
			||||||
 | 
					SrcColor         |     源颜色值 | 
				
			||||||
 | 
					SrcAlpha         |     源颜色的透明度值 | 
				
			||||||
 | 
					DstColor         |     目标颜色值 | 
				
			||||||
 | 
					DstAlpha         |     目标颜色的透明度值 | 
				
			||||||
 | 
					OneMinusSrcColor |     1-源颜色值 | 
				
			||||||
 | 
					OneMinusSrcAlpha |     1-源颜色的透明值 | 
				
			||||||
 | 
					OneMinusDstColor |     1-目标颜色值 | 
				
			||||||
 | 
					OneMinusDstAlpha |     1-目标颜色的透明度值 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					常用混合类型 | 
				
			||||||
 | 
					----------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					正常--------| Blend SrcAlpha OneMinusSrcAlpha | 
				
			||||||
 | 
					柔向相加----| Blend OneMinusDstColor One | 
				
			||||||
 | 
					正片叠底----| Blend DstColor Zero | 
				
			||||||
 | 
					两倍相乘----| Blend DstColor SrcColor | 
				
			||||||
 | 
					变暗--------| BlendOp Min | 
				
			||||||
 | 
					------------| Blend One One | 
				
			||||||
 | 
					变亮--------| BlendOp Max | 
				
			||||||
 | 
					------------| Blend One One | 
				
			||||||
 | 
					滤色--------| Blend OneMinusDstColor One | 
				
			||||||
 | 
					线性减淡----| Blend One One | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 4.Pass | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					渲染所使用的通道,可以使用抓取屏幕图像的Pass--GrabPass | 
				
			||||||
 | 
					以及引用其他shader的Pass--UsePass | 
				
			||||||
 | 
					以及自己编写的Pass | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 5.vert & frag | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					顶点着色器,编写案例如下 | 
				
			||||||
 | 
					需要前置结构体a2v | 
				
			||||||
 | 
					输出结构体v2f | 
				
			||||||
 | 
					(应用->顶点坐标->顶点着色器->输出顶点) | 
				
			||||||
 | 
					v2f vert (a2v v){ | 
				
			||||||
 | 
					    v2f o; | 
				
			||||||
 | 
					    //着色器内容 | 
				
			||||||
 | 
					    return o; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					需要前置结构体v2f | 
				
			||||||
 | 
					输出着色器颜色值fixed4 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(顶点->片元着色器->输出颜色) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fixed4 frag (v2f i) : SV_Target{ | 
				
			||||||
 | 
					 fixed4 tex = ...; | 
				
			||||||
 | 
					 //着色器内容 | 
				
			||||||
 | 
					 return tex; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 5.0 结构体语义(参考书籍P110) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### a2v------从应用阶段传递模型数据给顶点着色器 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| 语义          | 描述                                         | 类型            | | 
				
			||||||
 | 
					| ----------- | ------------------------------------------ | ------------- | | 
				
			||||||
 | 
					| POSITION    | 模型空间的顶点位置                                  | float4        | | 
				
			||||||
 | 
					| NORMAL      | 顶点法线                                       | float3        | | 
				
			||||||
 | 
					| TANGENT     | 顶点切线                                       | float3        | | 
				
			||||||
 | 
					| TEXCOORD0-7 | 该顶点的纹理坐标,可以定义TEXCOORD0,TEXCOORD1表示第一组或者第二组 | float2&float4 | | 
				
			||||||
 | 
					| COLOR       | 顶点颜色                                       | fixed4&float4 | | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### v2f------从顶点着色器传递数据给片元着色器 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| 语义          | 描述                | 类型     | | 
				
			||||||
 | 
					| ----------- | ----------------- | ------ | | 
				
			||||||
 | 
					| SV_POSITION | 裁剪空间中的顶点坐标        | float4 | | 
				
			||||||
 | 
					| COLOR0      | 通常用于输出第一组顶点颜色,非必需 | fixed4 | | 
				
			||||||
 | 
					| COLOR1      | 通常用于输出第二组顶点颜色,非必需 | fixed4 | | 
				
			||||||
 | 
					| TEXCOORD0-7 | 用于输出纹理坐标0-7       | 任意     | | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### SV_Target------片元着色器输出时用的语义 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输出值将会存储到渲染目标(Render Target)中。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### VPOS/WPOS------片元着色器传递屏幕坐标的语义 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					类型为float4,xy为屏幕空间中的坐标,z为近裁剪平面处于远裁剪平面处的分量,范围0-1。对于w,如果摄像机投影类型为正交投影,w恒为1,如果使用透视投影,w的取值范围为[1/Near,1/Far],Near为近裁剪平面处于摄像机的距离,Far为远裁剪平面处于摄像机的距离。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 5.1 变换矩阵(参考书籍P87) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_MVP(取模现在被UnityObjectToClipPos(v.vertex)所替代) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当前模型的观察投影矩阵,顶点/方向矢量 模型空间->裁剪空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_MV | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当前的模型观察矩阵,顶点/方向矢量 模型空间->观察空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_V | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当前的观察矩阵,顶点/方向矢量 世界空间->观察空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_P | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当前的投影矩阵,顶点/方向矢量 观察空间->裁剪空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_VP | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当前的观察投影矩阵,顶点/方向矢量 世界空间->裁剪空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_T_MV | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UNITY_MATRIX_MV的转置矩阵 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### UNITY_MATRIX_IT_MV | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UNITY_MATRIX_MV的逆转置矩阵,用于将发现从模型空间变换到观察空间,也可用于得到 | 
				
			||||||
 | 
					UNITY_MATRIX_MV的逆矩阵 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### unity_ObjectToWorld(原为_Object2World) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### unity_WorldToObject(原为_World2Object) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unity_ObjectToWorld的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 5.2 Unity内置的摄像机和屏幕参数(参考书籍P88) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 _WorldSpaceCameraPos | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该摄像机在世界空间中的位置 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 _ProjectionParams | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					x = 1.0 & -1.0 | y = Near | z = Far | w = 1.0 + 1.0 / Far | 
				
			||||||
 | 
					Near = 近裁剪平面到摄像机的距离 | 
				
			||||||
 | 
					Far = 远裁剪平面到摄像机的距离 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 _ScreenParams | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					x = width | y = height | z = 1.0 + 1.0 / width | w = 1.0 + 1.0 / height | 
				
			||||||
 | 
					width = 该摄像机的渲染目标的像素宽度 | 
				
			||||||
 | 
					height = 该摄像机的渲染目标的像素高度 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 _ZBufferParams | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					x = 1 - Far / Near | y = Far / Near | z = x / Far | w = y / Far | 
				
			||||||
 | 
					该变量用于线性化Z缓存中的深度值 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】unity_OrthoParams | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					x = width | y = height | z = 无定义 | w = 1.0(该摄像机为正交摄像机) & 0.0(该摄像机为透视摄像机) | 
				
			||||||
 | 
					width = 正交投影摄像机的宽度 | 
				
			||||||
 | 
					height = 正交投影摄像机的高度 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4x4】unity_CameraProjection | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该摄像机的投影矩阵 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4x4】unity_CameraInvProjection | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该摄像机的投影矩阵的逆矩阵 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4[6]】unity_CameraWorldClipPlanes[6] | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该摄像机的6个裁剪平面在世界空间下的等式 | 
				
			||||||
 | 
					按如下顺序:左、右、上、下、近、远裁剪平面 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 5.3 UnityCG.cginc常用的帮助函数(参考书籍P137) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					------------------------------------------------- | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 WorldSpaceViewDir(float4 v) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:模型空间中的顶点位置 | 
				
			||||||
 | 
					返回:世界空间红从该点到摄像机的观察方向。 | 
				
			||||||
 | 
					ps:内部实现使用了UnityWorldSpaceViewDir函数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 UnityWorldSpaceViewDir(float4 v) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:世界空间中的顶点位置 | 
				
			||||||
 | 
					返回:世界空间中从该点到摄像机的观察方向。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 ObjectSpaceViewDir(float4 v) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:一个模型空间中的顶点位置 | 
				
			||||||
 | 
					返回:模型空间中该点到摄像机的观察方向。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 WorldSpaceLightDir(float4 v)【仅用于前向渲染】【未被归一化】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:一个模型空间中的顶点位置 | 
				
			||||||
 | 
					返回:世界空间中从该点到光源的光照方向。 | 
				
			||||||
 | 
					ps:内部实现使用了UnityWorldSpaceLightDir函数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 UnityWorldSpaceLightDir(float4 v)【仅用于前向渲染】【未被归一化】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:世界空间中的顶点位置 | 
				
			||||||
 | 
					返回:世界空间中该点到光源的光照方向 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 ObjSpaceLightDir(float4 v)【仅用于前向渲染】【未被归一化】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:一个模型空间中的顶点位置 | 
				
			||||||
 | 
					返回:模型空间中从该点到光源的光照方向 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 UnityObjectToWorldNormal(float3 normal) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					把法线方向从模型空间转换到世界空间中 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 UnityObjectToWorldDir(float3 dir) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					把方向矢量从模型空间变换到世界空间中 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 UnityWorldToObjectDir(float3 dir) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					把方向矢量从世界空间变换到模型空间中 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 6.关于光照 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 6.1 Unity渲染路径 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					------------------------------------------------------------ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在tag-LightMode里设置,详情见本文2.2 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 6.2 Unity内置光照变量和函数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					------------------------------------------------------------ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 _LightColor0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该Pass处理的逐像素光源的颜色 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 _WorldSpaceLightPos0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该Pass处理的逐像素光源的位置。 | 
				
			||||||
 | 
					如果该光源是平行光,_WorldSpaceLightPos0.w=0 | 
				
			||||||
 | 
					如果是其他类型光,_WorldSpaceLightPos0.w=1 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4x4】 _LightMatrix0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					从世界空间到光源空间的变换矩阵。可以用于采样cookie和光照衰减纹理 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 unity_4LightPosX0 unity_4LightPosY0 unity_4LightPosZ0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					仅用于BasePass | 
				
			||||||
 | 
					前四个非重要的点光源在世界空间中的位置 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 unity_4LightPosX0 unity_4LightPosY0 unity_4LightPosZ0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					仅用于BasePass | 
				
			||||||
 | 
					前四个非重要的点光源在世界空间中的位置 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float4】 unity_4LightAtten0 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					仅用于BasePass | 
				
			||||||
 | 
					前四个非重要的点光源的衰减因子 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【half4[4]】 unity_LightColor | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					仅用于BasePass | 
				
			||||||
 | 
					前四个非重要的点光源的颜色 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 6.3 Unity前向渲染可以使用的内置光照参数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					------------------------------------------------------------ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					以下函数仅用于前向渲染才可使用。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 WorldSpaceLightDir(float4 v)【未被归一化】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:一个模型空间中的顶点位置 | 
				
			||||||
 | 
					返回:世界空间中从该点到光源的光照方向。 | 
				
			||||||
 | 
					ps:内部实现使用了UnityWorldSpaceLightDir函数 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 UnityWorldSpaceLightDir(float4 v)【未被归一化】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:一个世界空间中的顶点位置 | 
				
			||||||
 | 
					返回:世界空间中从该点到光源的光照方向。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 ObjSpaceLightDir(float4 v)【未被归一化】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:一个模型空间中的顶点位置 | 
				
			||||||
 | 
					返回:模型空间中从该点到光源的光照方向。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 【float3】 Shade4PointLights(...) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					输入:已经打包进矢量的光照数据,参考6.2 | 
				
			||||||
 | 
					返回:计算逐顶点光照。 | 
				
			||||||
| 
		 After Width: | Height: | Size: 11 KiB  | 
| 
		 After Width: | Height: | Size: 754 KiB  | 
| 
		 After Width: | Height: | Size: 36 KiB  | 
| 
		 After Width: | Height: | Size: 226 KiB  | 
| 
		 After Width: | Height: | Size: 4.2 KiB  | 
| 
		 After Width: | Height: | Size: 34 KiB  | 
| 
		 After Width: | Height: | Size: 36 KiB  | 
| 
		 After Width: | Height: | Size: 564 KiB  | 
| 
		 After Width: | Height: | Size: 757 KiB  | 
| 
		 After Width: | Height: | Size: 2.2 MiB  | 
| 
		 After Width: | Height: | Size: 80 KiB  | 
| 
		 After Width: | Height: | Size: 2.0 MiB  | 
| 
		 After Width: | Height: | Size: 2.5 MiB  | 
| 
		 After Width: | Height: | Size: 6.8 KiB  | 
| 
		 After Width: | Height: | Size: 8.5 KiB  | 
| 
		 After Width: | Height: | Size: 4.7 KiB  | 
| 
		 After Width: | Height: | Size: 5.2 KiB  | 
| 
		 After Width: | Height: | Size: 10 KiB  | 
| 
		 After Width: | Height: | Size: 10 KiB  | 
| 
		 After Width: | Height: | Size: 44 KiB  | 
| 
		 After Width: | Height: | Size: 4.8 KiB  | 
@ -0,0 +1,37 @@ | 
				
			|||||||
 | 
					# 法线贴图 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					法线贴图是一种用于表现平面倾斜度的数据。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					法线的取值范围是一个半球,如下图所示,处于半球边缘的任意点都可以代表法线的朝向。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					法线贴图实际是将每个点的法线方向,按照颜色rgba的方式存储。其中r代表x轴旋转度,g代表y轴旋转度,b实际是轴本身的旋转,几乎无意义所以基本恒为1。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					由于颜色值rgba属性中,不能为负值,取值范围为0-1之间的四组数值。所以将0.5作为垂直表面的法线基准值。故无凹凸表现的平面颜色值为(0.5,0.5,1,1);即为图中蓝点。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					图1 将坐标转换成颜色的图解 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					由于法线贴图不包含海拔信息,故向右凸起等于向左凹陷,反之向左凸起等于向右凹陷。比如下方图片旋转180度,感受一下是不是就像是凹陷了一样。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					图2 实际的法线贴图(包含一个凸出的八边形,如果旋转180度,则是凹陷的八边形) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# UnpackNormal函数应用 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					上一节讲了,由于法线贴图不能包含负值,所以在UnityShader的使用过程中,需要对法线进行一次变换,使之范围从原来的【 0 ~ 1 】转换为【 -1 ~ 1 】 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					故而 UnpackNormal ( packednormal ) = packednormal.xyz * 2 – 1 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					图2 执行完该方法后,会变成图3所示的样子 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					图3 UpackNormal 方法执行后 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					到这里可能会有人奇怪了,为什么左方跟下方都是一样的颜色。这个方法执行之后,实际上黑的部分是负数,负数的颜色是没法正确表现的,故变成了黑色。我们进行一次abs绝对值函数处理,就能看到对应颜色啦。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					图4 abs绝对值处理 | 
				
			||||||
@ -0,0 +1,195 @@ | 
				
			|||||||
 | 
					# 卡通水体的制作 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					话不多说,先上效果图 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该水体编写时,用到了GrabPass抓取屏幕,深度纹理,法线变换,菲涅尔反射,噪声纹理,以及顶点动画相关的知识 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					本篇中,仅解释编写原理,源码会在最后方放出,后续会不定期更新文档。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 水体部分 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 1.透明物体的制作 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					众所周知,水是大自然中透明的物体之一,首先我们需要做一个透明的物体。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					这时,我们可以用到GrabPass抓取屏幕与透明度混合两种方式编写。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					但由于透明度混合无法对后面的物体产生更改,故无法很好的模拟折射效果。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GrabPass抓取到图像后,经过变换获取到的视口空间中的坐标,从而模拟透明图像,这种方式做出来的透明图像,可以进行更多的操作,比如uv变换等等,可以很方便的模拟折射效果。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 2.使用法线贴图 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 3.模拟菲涅尔反射 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 4.模拟折射 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 浪花部分 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 1.深度纹理描边 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 2.泛光特效 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 3.使用噪声纹理模拟浪花 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##  | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 通过顶点动画让水体动起来 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 1.sin函数顶点变换 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 2.时间参数获取 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##  | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 全部代码 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c | 
				
			||||||
 | 
					//卡通水体 | 
				
			||||||
 | 
					//深度纹理与菲涅尔反射的综合应用 | 
				
			||||||
 | 
					Shader "Unlit/ToonWaterShader" | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    Properties | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        // 水体颜色 | 
				
			||||||
 | 
					        _WaterColor ("WaterColor", COLOR) = (1,1,1,1) | 
				
			||||||
 | 
					        // 浪花深度 | 
				
			||||||
 | 
					        _DepthScale("Depth Scale",Float) = 0.1 | 
				
			||||||
 | 
					        // 波浪噪声纹理 | 
				
			||||||
 | 
					        _WaveNoise("WaveTexture",2D) = "white" {} | 
				
			||||||
 | 
					        // 菲涅尔反射颜色 | 
				
			||||||
 | 
					        _ReflectColor ("Reflect Color",Color) = (0, 0, 1, 1) | 
				
			||||||
 | 
					        // 浅水区颜色 | 
				
			||||||
 | 
					        _DepthColor ("Depth Color",Color) = (0, 0, 1, 1) | 
				
			||||||
 | 
					        // 菲涅尔反射幅度 | 
				
			||||||
 | 
					        _FresnelScale ("Fresnel Scale", Range(0, 1)) = 1 | 
				
			||||||
 | 
					        // 水体法线 | 
				
			||||||
 | 
					        _BumpMap ("Normal Map", 2D) = "bump" {} | 
				
			||||||
 | 
					        // 法线影响度 | 
				
			||||||
 | 
					        _BumpScale("Bump Scale" ,Range(0,1)) = 1 | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    SubShader | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        Tags { "RenderType"="Opaque" "Queue"="Transparent" } | 
				
			||||||
 | 
					        LOD 100 | 
				
			||||||
 | 
					        //抓取屏幕图像,存在名为_RefractionTex的变量中 | 
				
			||||||
 | 
					        GrabPass { "_RefractionTex" } | 
				
			||||||
 | 
					        Pass | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            CGPROGRAM | 
				
			||||||
 | 
					            #pragma vertex vert | 
				
			||||||
 | 
					            #pragma fragment frag | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #include "UnityCG.cginc" | 
				
			||||||
 | 
					            // 声明抓取的变量 | 
				
			||||||
 | 
					            sampler2D _RefractionTex; | 
				
			||||||
 | 
					            float4 _RefractionTex_TexelSize; | 
				
			||||||
 | 
					            // 声明深度图 | 
				
			||||||
 | 
					            sampler2D _CameraDepthTexture; | 
				
			||||||
 | 
					            //声明Properties各项变量 | 
				
			||||||
 | 
					            sampler2D _WaveNoise; | 
				
			||||||
 | 
					            float4 _WaveNoise_ST; | 
				
			||||||
 | 
					            float _DepthScale; | 
				
			||||||
 | 
					            fixed4 _WaterColor; | 
				
			||||||
 | 
					            fixed4 _ReflectColor; | 
				
			||||||
 | 
					            fixed _FresnelScale; | 
				
			||||||
 | 
					            fixed4 _DepthColor; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sampler2D _BumpMap; | 
				
			||||||
 | 
					            float4 _BumpMap_ST; | 
				
			||||||
 | 
					            float _BumpScale; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //定义顶点着色器结构体 | 
				
			||||||
 | 
					            struct appdata | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                float4 vertex : POSITION; | 
				
			||||||
 | 
					                float2 uv : TEXCOORD0; | 
				
			||||||
 | 
					                float4 tangent : TANGENT; | 
				
			||||||
 | 
					                float3 normal : NORMAL; | 
				
			||||||
 | 
					            }; | 
				
			||||||
 | 
					            //定义片元着色器结构体 | 
				
			||||||
 | 
					            struct v2f | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                float2 uv : TEXCOORD0; | 
				
			||||||
 | 
					                float4 vertex : SV_POSITION; | 
				
			||||||
 | 
					                float4 scrPos : TEXCOORD1; | 
				
			||||||
 | 
					                float3 worldPos : TEXCOORD2; | 
				
			||||||
 | 
					                  fixed3 worldNormal : TEXCOORD3; | 
				
			||||||
 | 
					                  fixed3 worldViewDir : TEXCOORD4; | 
				
			||||||
 | 
					                //TBN矩阵 | 
				
			||||||
 | 
					                half3 wNormal : TEXCOORD5; | 
				
			||||||
 | 
					                half3 wTangent : TEXCOORD6; | 
				
			||||||
 | 
					                half3 wBitangent : TEXCOORD7; | 
				
			||||||
 | 
					            }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            v2f vert (appdata v) | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                v2f o; | 
				
			||||||
 | 
					                //定义偏移参数,根据时间变换顶点,使x轴顶点按照sin曲线运动 | 
				
			||||||
 | 
					                float4 offset; | 
				
			||||||
 | 
					                offset.xyzw = float4(0.0,0.0, 0.0, 0.0); | 
				
			||||||
 | 
					                //offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude; | 
				
			||||||
 | 
					                offset.x = cos(_Time.y + v.vertex.z)*0.3; | 
				
			||||||
 | 
					                o.vertex = UnityObjectToClipPos(v.vertex+offset); | 
				
			||||||
 | 
					                // | 
				
			||||||
 | 
					                o.uv = v.uv; | 
				
			||||||
 | 
					                o.scrPos = ComputeGrabScreenPos(o.vertex); | 
				
			||||||
 | 
					                o.worldNormal = UnityObjectToWorldNormal(v.normal); | 
				
			||||||
 | 
					                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; | 
				
			||||||
 | 
					                o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //计算TBN矩阵所用的三组变量。 | 
				
			||||||
 | 
					                o.wTangent = UnityObjectToWorldDir(v.tangent.xyz); | 
				
			||||||
 | 
					                o.wNormal = UnityObjectToWorldNormal(v.normal); | 
				
			||||||
 | 
					                // compute bitangent from cross product of normal and tangent | 
				
			||||||
 | 
					                // 通过计算法线与切线的叉积,得到二次切线bitangent,叉积*切线方向 | 
				
			||||||
 | 
					                // half tangentSign = v.tangent.w * unity_WorldTransformParams.w; | 
				
			||||||
 | 
					                // output the tangent space matrix | 
				
			||||||
 | 
					                half tangentSign = v.tangent.w; | 
				
			||||||
 | 
					                o.wBitangent = cross(o.wNormal, o.wTangent) * tangentSign; | 
				
			||||||
 | 
					                return o; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fixed4 frag (v2f i) : SV_Target | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					                fixed3 worldNormal = normalize(i.worldNormal); | 
				
			||||||
 | 
					                fixed3 worldViewDir = normalize(i.worldViewDir); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                half3 tnormal = UnpackNormal(tex2D(_BumpMap, i.uv)); | 
				
			||||||
 | 
					                float3x3 TBNMatrix = float3x3(i.wTangent,i.wBitangent,i.wNormal); | 
				
			||||||
 | 
					                worldNormal = mul(tnormal,TBNMatrix); | 
				
			||||||
 | 
					                //half3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos); | 
				
			||||||
 | 
					                half3 worldRefra = refract(worldViewDir,worldNormal,_BumpScale); | 
				
			||||||
 | 
					                float2 offset = worldRefra.xy; | 
				
			||||||
 | 
					                //i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // sample the texture | 
				
			||||||
 | 
					                //fixed4 refrCol = tex2D(_RefractionTex,i.uv); | 
				
			||||||
 | 
					                fixed4 refrCol = tex2D(_CameraDepthTexture, i.scrPos.xy/i.scrPos.w); | 
				
			||||||
 | 
					                i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy; | 
				
			||||||
 | 
					                fixed4 refrColScreen = tex2D(_RefractionTex,i.scrPos.xy/i.scrPos.w); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fixed4 WaveNoise = tex2D(_WaveNoise,i.uv); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); | 
				
			||||||
 | 
					                float linearDepth = LinearEyeDepth(refrCol.r); | 
				
			||||||
 | 
					                float diff = linearDepth - i.scrPos.w; | 
				
			||||||
 | 
					                fixed4 intersect = fixed4(1,1,1,1)-fixed4(diff*_DepthScale,diff*_DepthScale,diff*_DepthScale,1); | 
				
			||||||
 | 
					                fixed4 border = floor(saturate(intersect+WaveNoise)*2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fixed4 depthColor = (1-saturate(diff)) * _DepthColor; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fixed4 reflection = _ReflectColor; | 
				
			||||||
 | 
					                fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(worldViewDir, worldNormal), 5)*_BumpScale; | 
				
			||||||
 | 
					                fixed4 diffuse = _WaterColor*refrColScreen+depthColor+border; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fixed4 colorfinal = lerp(diffuse, reflection, saturate(fresnel)); | 
				
			||||||
 | 
					                return colorfinal; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            ENDCG | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||