复杂的光照与更复杂的阴影实现过程——ShaderCP9

 

——20.8.28缓存

 

这章的内容看了好久,也有不少复杂的内容。中途还有事情耽搁了一会。开学后就继续好好记录努力。app

咱们在游戏中能看到的让人以为真实感的来源之一就是真实的光照以及光照所产生的阴影。下面的内容分为两个部分一个是光照的部分一个是阴影的生成部分。ide

说到光照在Unity中渲染路径就是决定光照是以何种方式应用到Shader中的。因此要经过指定Pass通道的渲染路径类型 “LightMode” 来进行Shader的光照计算。简单地说就是设定渲染路径后Unity便会提供对应的光照信息给用户进行光照计算。函数

目前有三种渲染路径 1)前向渲染 2)延迟渲染(有新的) 3)顶点照明渲染(被抛弃)工具

当GPU不支持所选择的渲染路径则会降级性能

设置渲染路径即是在Tags设定 “LightMode” 有如下支持的的标签 测试

若是没有指定渲染路径可能会出错,由于此时看成为顶点照明渲染路径,当中的一些光照变量可能就不会被赋值。ui

1、前向渲染路径spa

每进行一次完整的前向渲染路径1.咱们须要渲染该对象的渲染图元2.计算两个缓冲区的信息 a.深度缓冲区(决定是否可见)b.颜色缓冲区(若可见,更新颜色缓冲区)对灯光范围内的物品每个灯光处理一次执行一次Pass设计

三种处理光照的方式 1)逐顶点处理 2)逐像素处理 3)球谐函数(SH)

一种光源的处理方式由类型和渲染模式(是否重要的,RenderMode)渲染一个物体要对光源进行排序(对物体的影响程度)要遵循如下规则 1)场景中最亮的平行光老是按逐像素处理2)渲染模式被设置为Not Important按逐顶点或是SH 3)渲染模式被设置为Important按逐像素处理 4)若是按以上规则获得的逐像素光源数量小于Quality Setting(PixelLight Count)将会由更多的光源按照逐像素处理

 

 

 

 注意事项:1.BasePass支持的光照特性 2.BasePass渲染的平行光默认有灯光 AddtivePass渲染的光源默认状况下没有阴影(即便设置了ShadowType)能够经过 #pragma multi_compile_fwdadd_fullshadows 代替 #pragma multi_compile_fwdadd 为点光源和聚光灯开启阴影 3.环境光(环境光和平行光不一样)和自发光在BasePass计算由于只计算一次在AdditivePass会致使屡次叠加 4.AdditivePass还要开启混合否则只有一个光源的影响 5.一个BassPass可定义屡次(好比双面渲染)但只运行一遍而AdditivePass会根据影响该物体的逐像素光源屡次调用 

 

以上是一些内置的函数和变量

2、顶点照明渲染

顶点照明可在前向渲染中完成,一个顶点照明的Pass最多8个逐顶点光源

 

3、延迟渲染路径

G缓冲 存储了离摄像机最近的表面的其余信息 包含两个单元第一个Pass计算哪些片元可见,第二个Pass利用G缓冲区中的信息光照计算。效率取决于场景的复杂度,而取决于屏幕空间大小。

优势 1)场景中的光源数目多,用前向渲染会形成性能瓶颈 2)每一个光源采用逐像素处理 缺点 1)不支持抗锯齿 2)不能处理半透明 3)对显卡由需求

分析完渲染路径以后咱们简单过一下基础的灯光类型在unity中存在的灯光类型以及它所具备的特色以及属性 1)平行光(不存在衰减 面向全局)2)点光源(边缘的强度为0,中间的衰减值能够用函数表示)3)聚光灯(同上,衰减计算更加复杂)4)面光源(只有烘培有用) 灯光所具备的基本特性 1)位置 2)方向 3)颜色 4)强度 5)衰减(到某点的衰减与距离有关)

UnityShader这本书只有对前向渲染有具体的内容,这里留一个延迟渲染路径的小坑(?)

主要就是注意要添加一个库“AutoLight.cginc” 其中有对以前对应渲染路径的内置变量定义,不然就找不到 好比_LightMatrix0之类

#ifdef USING_DIRECTIONAL_LIGHT
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // normalize(_WorldSpaceLightPos0.xyz);
#else
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
#endif

  这部分是在AdditivePass中的中区分平行光以及其余光源的光源方向。

#ifdef USING_DIRECTIONAL_LIGHT
fixed atten = 1.0;
#else
float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
//atten = 1.0;
#endif

  这里部分是最重要的这部分是在AdditivePass中对衰减的定义。在BasePass由于主要逐像素处理一个最重要的平行光 而平行光不存在衰减因此atten为1 而在AdditivePass须要区分平行光和其余光源 点光源采用对应函数进行衰减。在Unity中为了方便使用一张衰减纹理_LightTexture0来为光源计算衰减,首先要把对应距离灯光的点经过坐标运算从世界到光源空间。而后经过点乘也就是顶点距离的平方来进行纹理取样。来避免开方计算。上面的".rr"至关因而取x并定义float2(x,x)用于取样。UNITY_ATTEN_CHANNEL是衰减值所在的衰减通道。咱们不妨看一下这张_LightTexture0是什么样的图,就能理解为何要平方以后再取样。

 

 这张图就是按照平方值设计的。能够放到画图工具中发现它不是线性的。实际至关于一维坐标。由于只有x。

实际上这么分实际上是不够的由于其余灯光的聚光灯的衰减是不同的。这里暂时留一下(?)

// Upgrade NOTE: replaced '_LightMatrix0' with 'unity_WorldToLight'

Shader "Unlit/9-1ForwardRendering"
{
    Properties
    {
		_Diffuse("Diffuse", Color)= (1,1,1,1)
		_Specular("Specular", Color)= (1,1,1,1)
		_Gloss("Gloss", Range(8.0, 256))= 8
    }
    SubShader
    {
        Pass
        {
			Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
			#include "Lighting.cginc"
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
            };

            fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				fixed atten = 1.0;
				return fixed4(ambient + (diffuse + specular) * atten, 1.0);
            }
            ENDCG
        }

		Pass
		{
			Tags{ "LightMode"="ForwardAdd" }
			Blend One One
			CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdadd
			#include "Lighting.cginc"
            #include "UnityCG.cginc"
			#include "AutoLight.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
            };

            fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				#ifdef USING_DIRECTIONAL_LIGHT
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				#else
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
				#endif
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				#ifdef USING_DIRECTIONAL_LIGHT
				fixed atten = 1.0;
				#else
				float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
				fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				//atten = 1.0;
				#endif
				return fixed4((diffuse + specular) * atten, 1.0);
            }
            ENDCG
		}
    }FallBack "Specular"
}

  主要就是在以前的光照模型上区分了BasePass以及AdditivePass,须要指定渲染路径以及添加对应的#pragma。最后最主要的是增长灯光的衰减。咱们能够看一下实际效果。经过改变点光源的atten。足以看出衰减的真实感。衰减也能够用公式不用取样。同样后面继续研究(?)老留坑专家了。

 

 接下来即是最使人头大的阴影了。但又是最不可获取的部分。书中的理解部分会居多。

咱们先看一个概念ShadowMap。就是把摄像机放到光源重合的位置而后场景中的阴影就是摄像机看不见的位置。 (本质上是为了获得光源空间的深度图)

在前向渲染中,平行光开启阴影就会计算它的阴影映射纹理(shadowmap)。实际上他是一张深度图(mark一下后面的仔细研究一下深度的应用?)记录了从光源位置出发能看到离他位置最近的表面位置也就是深度信息。那具体是怎么判断距离光源最近的表面呢?有如下两种方法。1)就是用上面的这个ShadowMap方法,把摄像机放到光源位置而后经过前向渲染的BasePass/AdditivePass更新深度信息。可是使用这种正常渲染方式其中涉及狠毒复杂的光照模型计算因此很浪费 2)使用额外的Pass “LightMode”=“ShadowCaster” 渲染目标是阴影映射纹理不是帧缓存。首先同样是把摄像机放到光源位置而后调用该Pass(此事得到的深度信息是光源空间,由于和光源重合)。介绍了上述两个得到表面的方法,在unity中首先会a.找该Pass b.而后找FallBake(由于FallBack定义的默认Shader会有对阴影定义的ShadowCaster通道) c.若是都没有就没有阴影。

而后到了最后一步就是得到了对应的深度怎么把它应用到阴影上。阴影映射技术就是咱们须要看的 主要是由两种方法 1.传统方法,把正常的顶点坐标转换到光源空间,而后用xy份量对阴影映射纹理取样。若是深度小于改顶点的深度值也就是z份量则在阴影里。 2.屏幕空间的阴影投射技术。用阴影映射纹理以及摄像机(相机摆放位置即Game视图)的深度纹理经过这两张图获得屏幕空间的阴影图。摄像机记录的表面深度深度>其转换到阴影纹理的深度即为可见,但在该灯源的阴影中。而后对阴影图采样。

因此总结一下 两个过程 1.咱们想要让物体接受其余物体的阴影咱们就要对阴影图采样而后于光照结果相乘。2.咱们想要一个物体向其余物体投射阴影则须要把该物体加入阴影映射纹理的计算中。咱们下面进入实践过程。

 

 

 

咱们能够看到这张图发现有一点奇怪,物品命名有阴影可是这个平面却没有。主要缘由是平面在unity中只有一面渲染另外一面不渲染。因此解决方法即是改变平面的MeshRenderer中的CastShadow为TwoSides才能获得正确的阴影。

 

 

咱们看一下这张图发现这个方块没有接受到平面的阴影但本身却有阴影并且在Unity设置是正确的即有开启CastShadow 实际上之因此方块有阴影是由于采用了FallBack中的“ShadowCaster”的通道可是咱们能够从上图得知平面想要投射阴影须要加入阴影投射纹理。其实是输出片元的时候没有采样阴影映射纹理。咱们能够经过FrameBugger观察它的深度图。

 

 上面两张图是同样的阴影图。可是在渲染方块的时候却不同。

 

 

SHADOW_COORDS(2)//在v2f中的定义
TRANSFER_SHADOW(o);//在vert中
//在frag中
fixed shadow = SHADOW_ATTENUATION(i);
return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);

  首先SHADOW_COORDS(2)用于对阴影采样纹理的坐标里面的索引值是2也就对应的是TEXCOORD2.在片元函数中的就是进行阴影映射技术把信息存储到_ShadowCrood。SHADOW_ATTENUATION对纹理进行采样。要注意结构体的命名可能会致使定义的宏不可用。

// Upgrade NOTE: replaced '_LightMatrix0' with 'unity_WorldToLight'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/9-2Shadow"
{
    Properties
    {
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
			Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
			#pragma multi_compile_fwdbase
            #pragma vertex vert
            #pragma fragment frag
            #include "AutoLight.cginc"
			#include "Lighting.cginc"
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNoraml : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				SHADOW_COORDS(2)
            };

            fixed4 _Specular;
			fixed4 _Diffuse;
			float _Gloss;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNoraml = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				TRANSFER_SHADOW(o);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNoraml = normalize(i.worldNoraml);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNoraml, worldLightDir));
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular * pow(saturate(dot(worldNoraml, halfDir)), _Gloss);
				fixed atten = 1.0;
				fixed shadow = SHADOW_ATTENUATION(i);
				return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);
            }
            ENDCG
        }

		Pass
        {
			Tags { "LightMode"="ForwardAdd" }
			Blend One One
            CGPROGRAM
			#pragma multi_compile_fwdadd
			#pragma multi_compile_fwdadd_fullshadows
            #pragma vertex vert
            #pragma fragment frag
            #include "AutoLight.cginc"
			#include "Lighting.cginc"
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNoraml : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
            };

            fixed4 _Specular;
			fixed4 _Diffuse;
			float _Gloss;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNoraml = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNoraml = normalize(i.worldNoraml);
				#ifdef USING_DIRECTIONAL_LIGHT
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				#else
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
				#endif
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNoraml, worldLightDir));
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular * pow(saturate(dot(worldNoraml, halfDir)), _Gloss);
				#ifdef USING_DIRECTIONAL_LIGHT
					fixed atten = 1.0;
				#else
					float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
					fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				#endif
				return fixed4((diffuse + specular) * atten , 1.0);
            }
            ENDCG
        }
    }FallBack "Specular"
}

 

如今咱们就有平面的投影了。

 

UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

  这个函数是能够直接统一管理衰减以及阴影。不须要定义atten能够直接用。

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/9-3AttenuationAndShadowUseBuildInFunc"
{
    Properties
    {
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
			Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
			#pragma multi_compile_fwdbase
            #pragma vertex vert
            #pragma fragment frag
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				SHADOW_COORDS(2)
            };

			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				TRANSFER_SHADOW(o);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				return fixed4(ambient + (diffuse + specular) * atten, 1.0);
            }
            ENDCG
        }

		Pass
        {
			Tags { "LightMode"="ForwardAdd" }
            CGPROGRAM
			#pragma multi_compile_fwdadd
			#pragma multi_compile_fwdadd_fullshadows
            #pragma vertex vert
            #pragma fragment frag
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				SHADOW_COORDS(2)
            };

			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				TRANSFER_SHADOW(o);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				return fixed4((diffuse + specular) * atten, 1.0);
            }
            ENDCG
        }
    }
}

  这样BasePass和AdditivePass就能够统一。

最后就是上一节的一个小坑也是填上了。就是半透明物体的阴影关系。

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/9-4AlphaTestWithShadow"
{
    Properties
    {
        _Color("Color", Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}
		_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="TransparentCutOut" "IgnoreProjector"="True" "Queue"="AlphaTest" }
        Pass
        {
			Tags{ "LightMode"="ForwardBase" }

			Cull Off

            CGPROGRAM
			#pragma multi_compile_fwdbase
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"
			#include "AutoLight.cginc"
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;
            };

            struct v2f
            {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float2 uv : TEXCOORD2;
				SHADOW_COORDS(3) //TEXCOORD3
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			fixed4 _Color;
			fixed _Cutoff;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				TRANSFER_SHADOW(o);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed4 texColor = tex2D(_MainTex, i.uv);
				clip(texColor.a - _Cutoff);
				fixed3 albedo = texColor.rgb * _Color.rgb;
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLightDir));
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				return fixed4(ambient + diffuse * atten, 1.0);
            }
            ENDCG
        }
    }
  //FallBack "VertexLit"
  FallBack "Transparent/Cutout/VertexLit" }

  首先是透明测试的投影。效果图以下。图一是表示可以正常的接受阴影。图二图三分别是采用不一样的FallBack的效果后者相对于前者是比较正确的。最后一张图是是否打开CastShadow中的TwoSides左边是打开的能够看出正方形的内部投影是和左边相比体现了处理。

 

 最后是透明度混合的阴影。一样的增长FallBack

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/9-5AlphaBlendWithShadow"
{
    	Properties {
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_MainTex ("Main Tex", 2D) = "white" {}
		_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
	}
	SubShader {
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		
		Pass {
			Tags { "LightMode"="ForwardBase" }
			
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha
			
			CGPROGRAM
			
			#pragma multi_compile_fwdbase
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _AlphaScale;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float2 uv : TEXCOORD2;
				SHADOW_COORDS(3)
			};
			
			v2f vert(a2v v) {
			 	v2f o;
			 	o.pos = UnityObjectToClipPos(v.vertex);
			 	
			 	o.worldNormal = UnityObjectToWorldNormal(v.normal);
			 	
			 	o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

			 	o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
			 	
			 	// Pass shadow coordinates to pixel shader
			 	TRANSFER_SHADOW(o);
			 	
			 	return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				
				fixed4 texColor = tex2D(_MainTex, i.uv);
				
				fixed3 albedo = texColor.rgb * _Color.rgb;
				
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));

			 	// UNITY_LIGHT_ATTENUATION not only compute attenuation, but also shadow infos
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
			 	
				return fixed4(ambient + diffuse * atten, texColor.a * _AlphaScale);
			}
			
			ENDCG
		}
	} 
	//FallBack "Transparent/VertexLit"
	// Or  force to apply shadow
	FallBack "VertexLit"
}

  采用FallBack "VertexLit"会强制投影同时接受阴影。"Transparent/VertexLit"二者都不会。主要是半透明物体因为关闭了深度写入也会影响对应阴影的生成。

 

这就是最后了。感谢您读到这里。Cheers!

 PS:这章总算是看完了。还留了不少坑。慢慢补把。

相关文章
相关标签/搜索