shader shadow(物体接收阴影与产生阴影)

光照衰减
Unity在内部使用一张名为_LightTexture0的纹理来计算光源衰减。我们通常只关心_LightTexture0对角线上的纹理颜色值,这些值表明了再光源空间中不同位置的点的衰减值。例如(0,0)点表明了与光源位置重合的点的衰减值,而(1,1)点表明了再光源空间中所关心的距离最远的点的衰减。

float3 lightCoord = mul(_LightMatrix0,float4(i.worldPos,1)).xyz;
fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;

现将世界坐标与_LightMatrix0相乘得到在光源空间中的位置,用光源空间中顶点距离的平方来对纹理采样,然后,使用宏UINITY_ATTEN_CHANNEL来得到衰减纹理中的衰减值所在的分量,以得到最终的衰减值。

数学公式计算光照衰减
float distance = length(_WorldSpaceLightPos0.xyz - i.worldPosition.xyz);
atten = 1.0/distance;

Unity中阴影
1,Shadow Map:它会首先把摄像机位置放在与光源重合的位置上,那么场景中该光源的阴影区域就是摄像机看不到的地方。
2,Screenspace Shadow Map:Unity首先会通过调用LightMode 为 ShadowCaster的Pass来得到可投射阴影是光源的阴影映射纹理以及摄像机的深度纹理。然后,根据光源的阴影映射纹理和摄像机的深度纹理来得到屏幕空间的阴影图。如果摄像机的深度图中记录的表面深度大于转换到阴影映射纹理中的深度值,就说明该表面虽然是可见的,但是却出于该光源的阴影中。通过这样的方式,阴影图就包含了屏幕空间中所有阴影的区域。如果我们想要一个物体接收来自其他物体的阴影,只需要在Shader中对阴影图进行采样。

一个物体接收来自其他物体的阴影,以及它向其他物体投射阴影是两个过程。
1,如果我们想要一个物体接收来自其他物体的阴影,就必须在Shader中对阴影映射纹理(包括屏幕空间的阴影图)进行采样,把采样结果和最后的光照结果相乘来产生阴影效果。
2,如果我们想要一个物体向其他物体投射阴影,就必须把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样时可以得到该物体的相关信息。在Unity 中,这个过程通过为该物体执行LightMode 为ShadowCaster 的 Pass 来实现的。如果使用了屏幕空间的投射映射技术,Unity还会使用这个Pass 产生一张摄像机的深度纹理。

接收两层阴影

在这里插入图片描述
主要代码在第一个Pass中
代码如下:

Shader "MyShader/shadow"
{
    Properties
	{
		_Diffuse("diffuse",Color) = (1,1,1,1)
		_Specular("specular",Color) = (1,1,1,1)
		_Gloss("gloss",Range(1,256)) = 20
	}
	SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

		Pass//ForwardBase
		{
			Tags{"LightMode"="ForwardBase"}
			CGPROGRAM
			#pragma multi_compile_fwdbase
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
		
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

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

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal:TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				float3 vertexLight : TEXCOORD2;
				SHADOW_COORDS(3)//仅仅是阴影
            };


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

#ifdef LIGHTMAP_OFF
				float3 shLight = ShadeSH9(float4(v.normal, 1.0));
				o.vertexLight = shLight;
#ifdef VERTEXLIGHT_ON
				float3 vertexLight = Shade4PointLights(
					unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
					unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
					unity_4LightAtten0, o.worldPos, o.worldNormal
				);
				o.vertexLight += vertexLight;
#endif
#endif
				TRANSFER_SHADOW(o);//仅仅是阴影
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

				float3 worldNormal = normalize(i.worldNormal);
				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - 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);

				//fixed shadow = SHADOW_ATTENUATION(i);
				//return fixed4(ambient + (diffuse + specular)*shadow + i.vertexLight, 1);

				//这个函数计算包含了光照衰减以及阴影,因为ForwardBase逐像素光源一般是方向光,衰减为1,atten在这里实际是阴影值
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				return fixed4(ambient + (diffuse + specular)*atten +i.vertexLight, 1);
            }
            ENDCG
        }

		Pass//ForwardAdd
		{
			Tags{"LightMode"="ForwardAdd"}
			Blend One One

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

			float4 _Diffuse;
			float4 _Specular;
			float _Gloss;

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

			struct v2f
			{
				float4 pos:SV_POSITION;
				float3 worldPos:TEXCOORD0;
				float3 worldNormal:TEXCOORD1;
				LIGHTING_COORDS(2, 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;
				TRANSFER_VERTEX_TO_FRAGMENT(o);//包含光照衰减以及阴影
				return o;
			}

			fixed4 frag(v2f i):SV_Target
			{
				float3 worldNormal = normalize(i.worldNormal);
				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

				fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal, worldLightDir));

				float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				float3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				//fixed atten = LIGHT_ATTENUATION(i);
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);//包含光照衰减以及阴影
				return fixed4((diffuse + specular)*atten, 1);
			}
			ENDCG
		}

		Pass//产生阴影的通道(物体透明也产生阴影)
		{
			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
		}
    }
}

如果没能接收两层阴影,Editor–>Project Settings–>Player, 在Other Settings中找到Color Space,将Gamma改为Linear就可以了。

半透半不透物体产生阴影

在这里插入图片描述

Shader "MyShader/shadow2"
{
	Properties
	{
		_Cutoff("cutoff",Range(0,1))=0.5//控制透明
		_MainTex("main texture",2D)="white"{}
		_Color("diffuse",Color) = (1,1,1,1)
		_Specular("specular",Color) = (1,1,1,1)
		_Gloss("gloss",Range(1,256)) = 20
	}
	SubShader
	{
		Tags { "RenderType" = "TransparentCutOut" "Queue"="AlphaTest" "IgnoreProjector"="True" }
		LOD 100

		Pass//ForwardBase
		{
			Tags{"LightMode" = "ForwardBase"}
			CGPROGRAM
			#pragma multi_compile_fwdbase
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"

			fixed4 _Color;
			fixed4 _Specular;
			float _Gloss;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _Cutoff;

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

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


			v2f vert(appdata 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.uv, _MainTex);
				TRANSFER_SHADOW(o);//仅仅是阴影
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

				float3 worldNormal = normalize(i.worldNormal);
				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);

				fixed4 texColor = tex2D(_MainTex, i.uv);
				clip(texColor.a - _Cutoff);//控制透明

				fixed3 diffuse = texColor.rgb*_LightColor0.rgb*_Color.rgb*saturate(dot(worldNormal, worldLightDir));

				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal, halfDir)), _Gloss);

				//fixed shadow = SHADOW_ATTENUATION(i);
				//return fixed4(ambient + (diffuse + specular)*shadow + i.vertexLight, 1);

				//这个函数计算包含了光照衰减以及阴影,因为ForwardBase逐像素光源一般是方向光,衰减为1,atten在这里实际是阴影值
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				return fixed4(ambient + (diffuse + specular)*atten, 1);
			}
			ENDCG
		}

		Pass//ForwardAdd
		{
			Tags{"LightMode" = "ForwardAdd"}
			Blend One One

			CGPROGRAM
			#pragma multi_compile_fwdadd_fullshadows
			#pragma vertex vert
			#pragma fragment frag

			#include"UnityCG.cginc"
			#include"Lighting.cginc"
			#include"AutoLight.cginc"

			float4 _Diffuse;
			float4 _Specular;
			float _Gloss;

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

			struct v2f
			{
				float4 pos:SV_POSITION;
				float3 worldPos:TEXCOORD0;
				float3 worldNormal:TEXCOORD1;
				LIGHTING_COORDS(2, 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;
				TRANSFER_VERTEX_TO_FRAGMENT(o);//包含光照衰减以及阴影
				return o;
			}

			fixed4 frag(v2f i) :SV_Target
			{
				float3 worldNormal = normalize(i.worldNormal);
				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

				fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal, worldLightDir));

				float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				float3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				//fixed atten = LIGHT_ATTENUATION(i);
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);//包含光照衰减以及阴影
				return fixed4((diffuse + specular)*atten, 1);
			}
			ENDCG
		}
			 
		Pass//产生阴影的通道(物体透明了就不会产生阴影)
		{
			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;
				float2  uv : TEXCOORD1;
				UNITY_VERTEX_OUTPUT_STEREO
			};

			uniform float4 _MainTex_ST;

			v2f vert(appdata_base v)
			{
				v2f o;
				UNITY_SETUP_INSTANCE_ID(v);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
				TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				return o;
			}

			uniform sampler2D _MainTex;
			uniform fixed _Cutoff;
			uniform fixed4 _Color;

			float4 frag(v2f i) : SV_Target
			{
				fixed4 texcol = tex2D(_MainTex, i.uv);
				clip(texcol.a*_Color.a - _Cutoff);

				SHADOW_CASTER_FRAGMENT(i)
			}
			ENDCG
		}
	}
	//FallBack "Diffuse"
	//FallBack "Transparent/Cutout/VertexLit"
}

透明或者半透明或者不透明物体都能产生和接收阴影

在这里插入图片描述

代码如下:

Shader "MyShader/shadow3"
{
	Properties
	{
		_AlphaScale("cutoff",Range(0,1)) = 0.5//透明程度
		_MainTex("main texture",2D) = "white"{}
		_Color("diffuse",Color) = (1,1,1,1)
		_Specular("specular",Color) = (1,1,1,1)
		_Gloss("gloss",Range(1,256)) = 20
	}
		SubShader
		{
			Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True" }
			LOD 100

			Pass//ForwardBase
			{
				Tags{"LightMode" = "ForwardBase"}
				ZWrite Off
				Blend SrcAlpha OneMinusSrcAlpha

				CGPROGRAM
				#pragma multi_compile_fwdbase
				#pragma vertex vert
				#pragma fragment frag

				#include "UnityCG.cginc"
				#include "Lighting.cginc"
				#include "AutoLight.cginc"

				fixed4 _Color;
				fixed4 _Specular;
				float _Gloss;
				sampler2D _MainTex;
				float4 _MainTex_ST;
				float _AlphaScale;

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

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


				v2f vert(appdata 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.uv, _MainTex);
					TRANSFER_SHADOW(o);//仅仅是阴影
					return o;
				}

				fixed4 frag(v2f i) : SV_Target
				{
					fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

					float3 worldNormal = normalize(i.worldNormal);
					float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
					float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);

					fixed4 texColor = tex2D(_MainTex, i.uv);

					fixed3 diffuse = texColor.rgb*_LightColor0.rgb*_Color.rgb*saturate(dot(worldNormal, worldLightDir));

					fixed3 halfDir = normalize(viewDir + worldLightDir);
					fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal, halfDir)), _Gloss);

					//fixed shadow = SHADOW_ATTENUATION(i);
					//return fixed4(ambient + (diffuse + specular)*shadow + i.vertexLight, 1);

					//这个函数计算包含了光照衰减以及阴影,因为ForwardBase逐像素光源一般是方向光,衰减为1,atten在这里实际是阴影值
					UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
					return fixed4(ambient + (diffuse + specular)*atten, texColor.a*_AlphaScale);
				}
				ENDCG
			}

			//Pass//ForwardAdd
			//{
			//	Tags{"LightMode" = "ForwardAdd"}
			//	Blend One One

			//	CGPROGRAM
			//	#pragma multi_compile_fwdadd_fullshadows
			//	#pragma vertex vert
			//	#pragma fragment frag

			//	#include"UnityCG.cginc"
			//	#include"Lighting.cginc"
			//	#include"AutoLight.cginc"

			//	float4 _Diffuse;
			//	float4 _Specular;
			//	float _Gloss;

			//	struct a2v
			//	{
			//		float4 vertex:POSITION;
			//		float3 normal:NORMAL;
			//	};

			//	struct v2f
			//	{
			//		float4 pos:SV_POSITION;
			//		float3 worldPos:TEXCOORD0;
			//		float3 worldNormal:TEXCOORD1;
			//		LIGHTING_COORDS(2, 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;
			//		TRANSFER_VERTEX_TO_FRAGMENT(o);//包含光照衰减以及阴影
			//		return o;
			//	}

			//	fixed4 frag(v2f i) :SV_Target
			//	{
			//		float3 worldNormal = normalize(i.worldNormal);
			//		float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

			//		fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal, worldLightDir));

			//		float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
			//		float3 halfDir = normalize(viewDir + worldLightDir);
			//		fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal, halfDir)), _Gloss);
			//		//fixed atten = LIGHT_ATTENUATION(i);
			//		UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);//包含光照衰减以及阴影
			//		return fixed4((diffuse + specular)*atten, 1);
			//	}
			//	ENDCG
			//}

			
		}
		FallBack "Diffuse"
		//FallBack "Transparent/Cutout/VertexLit"
}

把Render Queue改为Transparent以下的值,比如改成AlphaTest,半透明物体也能接收阴影了。

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值