Untiy3d ShaderLab球体阴影(三) 点光源对球体的投影
发表于2017-05-06
本篇文章要介绍的是球体阴影中点光源对球体的投影,与平行光对平面的投影原理是一样的,具体方法大家可以看看代码部分是如何实现的。
如图所示,淡黄色的是阴影的淡入淡出,淡紫色的是点光源的阴影。在接受阴影的Shader 中计算了平行光和点光源两种阴影。与平行光对平面的投影原理差不多,这里就不多说了。
具体实现的是:
Shader "Tut/Shadow/SphereShadow_3" { Properties { _spPos ("Sphere Position", vector) = (0,0,0,1) _spR ("Sphere Radius", float) = 1 _Intensity("Intensity Of Shadow",range(0,1))=0.5 } SubShader { pass{ Tags{"LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float4 _spPos; float _spR; float _Intensity; float4 _LightColor0; struct v2f{ float4 pos:SV_POSITION; float3 litDir:TEXCOORD0; float3 spDir:TEXCOORD1; float4 vc:TEXCOORD2; }; v2f vert(appdata_base v) { v2f o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); o.litDir=WorldSpaceLightDir(v.vertex); o.spDir=(_spPos-mul(_Object2World,v.vertex)).xyz; float3 ldir=ObjSpaceLightDir(v.vertex); ldir=normalize(ldir); o.vc=_LightColor0*max(0,dot(ldir,v.normal)); return o; } float4 frag(v2f i):COLOR { float3 litDir=normalize(i.litDir); float3 spDir=i.spDir; float spDistance=length(spDir); spDir=normalize(spDir); float cosV=dot(spDir,litDir); float sinV=sin(acos(max(0,cosV))); float D=sinV*spDistance; float shadow=step(_spR,D);//spR>D 0,else 1 float atten=pow((D/_spR),4); float c=lerp(1-_Intensity,1,min(1,shadow+atten));//0 is dark //*step(0,dot(i.N,litDir)) return i.vc*c; } ENDCG }//endpass pass{ Tags{"LightMode"="ForwardAdd"} Blend One One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float4 _spPos; float _spR; float _Intensity; float4 _LightColor0; struct v2f{ float4 pos:SV_POSITION; float3 litDir:TEXCOORD0; float3 spDir:TEXCOORD1; float4 vc:TEXCOORD2; }; v2f vert(appdata_base v) { v2f o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); o.litDir=WorldSpaceLightDir(v.vertex); o.spDir=(_spPos-mul(_Object2World,v.vertex)).xyz; float3 ldir=ObjSpaceLightDir(v.vertex); float atten=1/(1+length(ldir)); ldir=normalize(ldir); o.vc=_LightColor0*max(0,dot(ldir,v.normal))*atten; return o; } float4 frag(v2f i):COLOR { float litAtten=length(i.litDir); float3 litDir=normalize(i.litDir); float3 spDir=i.spDir; float spDistance=length(spDir); spDir=normalize(spDir); float cosV=dot(spDir,litDir); float sinV=sin(acos(max(0,cosV))); float D=sinV*spDistance; float shadow=step(0,D-_spR);//spR>D 0,else 1 float atten=pow((D/_spR),4); float c=lerp(1-_Intensity,1,min(1,shadow+atten));//0 is dark //*step(0,dot(i.N,litDir))// return c*i.vc; } ENDCG }//endpass } }