阴影处理
1、物体能投射阴影以及物体能接受阴影为两个方面。
a.物体投射阴影在unity中应该打开CastShadow选项。这样物体深度就可以加入到深度纹理的计算中,从而影响深度纹理中的depth值。这个深度纹理生成unity3D中采用的方法与OpenGL大同小异,即:以光源位置,光源方向为相机参数,得到相应的深度纹理。
b.物体接受阴影,这个过程是判断正常相机下看到的片段是否在阴影中,采用的方法是传递光源下相机的MVP,然后做position变换到clip空间,然后对(x,y)做[0,1]处理,根据这个处理后的值对上一步中的深度纹理进行采样得到相应的深度d0,如果d0<postion.z([0,1]变换后的depth值),说明这个片段在阴影中,应该对颜色进行乘以shadow值。
2、Unity3D shader中写法。
unity3d中让物体参与到阴影纹理的生成中,除了castShadow打开外,要在pass中执行上述说的深度纹理生成,此过程一般不放到basePass与addtionPass中,因为这两个pass一般进行光照计算,而深度纹理计算只是得到深度纹理,因此可以使用一个单独的pass,即“LightMode” = “ShadowCaster”的pass来得到。而这个pass一般在FallBack “Diffuse”等FallBack中得到。
接受纹理可以用下面步骤:
a.单独处理shadow可以在v2f中添加SHADOW_COORD(x) ,x为下一个可以使用的寄存器编号。注意使用这个宏最后不加“;”,因为这个定义是在struct中,且在“autolight.cginc”的定义中已经添加了最后的分号。
b.在vert中使用TRANSFER_SHADOW(o);这个宏可以将v2f变量o中的纹理采样坐标变换得到相应的屏幕空间纹理,为采样深度纹理使用。
c.在frg中使用SHADOW_ATTENUTION(i),计算对应的fragment是否在shadow中,这个宏返回一个fixed值,然后将此值与frag中得到的col值相乘,即可得到相应的阴影效果。
3、实例代码
Shader "FFD/shadow1"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//要想有正确的衰减内置变量等,必须要有这句
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "autolight.cginc"
#include "lighting.cginc"
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
SHADOW_COORDS(1) //宏表示为定义一个float4的采样坐标,放到编号为1的寄存器中
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
TRANSFER_SHADOW(o) //根据变换求解上面结构体中的float4坐标,unity5中采用的是屏幕空间阴影贴图
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
fixed shadow = SHADOW_ATTENUATION(i); //根据贴图与纹理坐标对纹理采样得到shadow值。
col = col*shadow; //最终影响光照
return col;
}
ENDCG
}
}
FallBack "Specular"
}
网友评论