前向渲染中在fwdadd中实现点光源的阴影效果
- 实现效果
- 错误结果
- 具体步骤如下
- 1. 选择光源的阴影类型
- 2. 为材质勾选接收阴影和投射阴影选项
- 3. shader设置
- 补充
实现效果
可以看到不仅有平行光照射在底面上的投影,点光源在竖直面板上的投影也出现了,达到了预期效果。
错误结果
平行光的阴影投射在底面上,但是点光源光线穿过了物体直接投射在竖直平面上,显然不对,问题出在点光源在初始时没有选择阴影类型,使得在最初的UpdateDepthTexture步骤就没有生成阴影。
具体步骤如下
1. 选择光源的阴影类型
这一步被我忽视了,昨天一直找不到原因,导致最后的实现结果中只有光线衰减而看不到点光源投射的阴影。
在这里选择了soft shadow类型。
2. 为材质勾选接收阴影和投射阴影选项
3. shader设置
ForwardBase中需要导入“AutoLight.cginc”
#include "AutoLight.cginc"
在struct v2f 中调用宏
struct v2f{
float4 pos :SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
// 宏
SHADOW_COORDS(2)
};
在顶点着色器中添加相关操作,对输出的o进行转化
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;
}
最后在片元着色器中获得光照的衰减值和阴影值(统一为atten)
fixed4 frag(v2f i):SV_Target{
fixed shadow = SHADOW_ATTENUATION(i);
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(halfDir,worldNormal)),_Gloss);
// 该函数得到衰减值相关,返回值填充到第一个参数的位置中,即atten
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
return fixed4(ambient+(diffuse+specular)*atten,1.0);
}
fwdadd中类似,但是注意将
#pragma multi_compile_fwdadd
替换成
#pragma multi_compile_fwdadd_fullshadows
因为fwdadd中默认不开启阴影设置,其他与fwdbase中的配置完全相同。
补充
在我的shader中没有引入LightMode为ShadowCaster的pass,但是结果还是出现了,因为在最后使用了Fallback"Specular"等方法, 当渲染过程中在当前shader中没有找到ShadowCaster的pass时,就会向上寻找,从而在Fallback中找到对应的pass,最终实现阴影效果。
值得注意的是,霜狼_May的教程中有提到,建议还是自己将那一段pass写在自己的shader中,防止fallback引入过多无用的pass扰乱结果的生成。