阴影实现
屏幕空间的阴影映射技术
调用LightMode为shadowcaster的pass得到阴影纹理映射和摄像机的深度纹理,根据这两张图来得到屏幕空间的阴影图(在摄像机的深度中但不在光源的深度中:可见的阴影)
接受阴影:采样结果和光照结果相乘
投射阴影:把该物体加入阴影映射纹理的计算中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Pass { Name "ShadowCaster" Tags { "LightMode" = "ShadowCaster" } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_shadowcaster #pragma multi_compile_instancing // allow instanced shadow pass for most of the shaders #include "UnityCG.cginc" struct v2f { V2F_SHADOW_CASTER; UNITY_VERTEX_OUTPUT_STEREO }; v2f vert ( appdata_base v ) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) return o; } float4 frag ( v2f i ) : SV_Target { SHADOW_CASTER_FRAGMENT(i) } ENDCG }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 Shader "Unity Shaders Book/Chapter 9/Shadow" { 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" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2 ) }; v2f vert (a2v v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0 , dot(worldNormal, 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 vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 position : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; v2f vert (a2v v ) { v2f o; o.position = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); #ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); #else fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); #endif fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0 , 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; #endif return fixed4((diffuse + specular) * atten, 1.0 ); } ENDCG } } FallBack "Specular" }
统一管理光照衰减和阴影
使用内置宏UNITY_LIGHT_ATTENUATION
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 Shader "Unity Shaders Book/Chapter 9/Attenuation And Shadow Use Build-in Functions" { 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" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2 ) }; v2f vert (a2v v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0 , dot(worldNormal, halfDir)), _Gloss); UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4(ambient + (diffuse + specular) * atten, 1.0 ); } ENDCG } Pass { Tags { "LightMode" ="ForwardAdd" } Blend One One CGPROGRAM #pragma multi_compile_fwdadd #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2 ) }; v2f vert (a2v v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0 , dot(worldNormal, halfDir)), _Gloss); UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4((diffuse + specular) * atten, 1.0 ); } ENDCG } } FallBack "Specular" }
透明物体的阴影 在Fallback中调用“Transparent/Cutout/VertexLit”