剪切造成的阴影
目前,我们透明材质的阴影总是像是由不透明材质投射的一样,因为这是我们的着色器所假设的一个条件。因此,阴影可能会显得很奇怪,直到你意识到你看到的是一个不透明对象所投射的阴影。在方向光生成的阴影情况下,这也可以导致不可见的几何体遮挡阴影。
在不透明渲染模式和剪切渲染模式下,所得到的方向阴影是相同的。
在聚光灯或点光源生成光影的情况下,你会得到一个实心的阴影。
实心的聚光灯阴影。
重构我的阴影
为了把透明度考虑进来,我们必须访问阴影投射着色器渲染通道中的透明度值。这意味着我们需要对反射率纹理进行采样。但是,当使用不透明渲染模式的时候,我们不需要对反射率纹理进行采样。所以我们需要为我们的阴影使用多个着色器变体。
现在我们有两个版本的阴影程序。 一个版本用于立方体阴影贴图,这是点光源所需的,一个用于其他光源类型。现在我们需要混合更多的变体。为了使混合更多的变体更容易,我们将重写My Shadow这个导入文件。我们将为所有变体使用插值器,并创建单个顶点和片段程序。
首先,将Interpolator的定义移出条件块。然后使光向量成为条件。
structVertexData {
float4 position : POSITION;
float3 normal : NORMAL;
};
structInterpolators {
float4 position : SV_POSITION;
#if defined(SHADOWS_CUBE)
float3 lightVec : TEXCOORD0;
#endif
};
接下来,写一个新的顶点程序,其中包含两个不同版本的副本。非立方体的代码必须稍微调整以使用新的Interpolator输出。
Interpolators MyShadowVertexProgram (VertexData v) {
Interpolators i;
#if defined(SHADOWS_CUBE)
i.position = UnityObjectToClipPos(v.position);
i.lightVec =
mul(unity_ObjectToWorld, v.position).xyz - _LightPositionRange.xyz;
#else
i.position = UnityClipSpaceShadowCasterPos(v.position.xyz, v.normal);
i.position = UnityApplyLinearShadowBias(i.position);
#endif
returni;
}
对片段程序执行相同操作。然后摆脱旧的条件程序
float4 MyShadowFragmentProgram (Interpolators i) : SV_TARGET {
#if defined(SHADOWS_CUBE)
floatdepth = length(i.lightVec) + unity_LightShadowBias.x;
depth *= _LightPositionRange.w;
returnUnityEncodeCubeShadowDepth(depth);
#else
return0;
#endif
}
//#if defined(SHADOWS_CUBE)
// …
//#endif
裁剪阴影片段
我们首先处理剪切造成的阴影。 我们通过丢弃片段在阴影中切孔,就像我们在剪切渲染模式中的其他渲染过程中所做的那样。为达到这个目的,我们需要材料的色调、反射率纹理和透明度截止阈值这些信息。在My Shadows的顶部为它们添加相应的变量。
#include "UnityCG.cginc"
float4 _Tint;
sampler2D _MainTex;
float4 _MainTex_ST;
float_AlphaCutoff;
因此,当我们使用剪切渲染模式的时候,我们必须对反射率纹理进行采样。实际上,当我们不使用反射率纹理的透明度值来确定平滑度的时候我们必须这样做。当满足这些条件的时候,我们必须将UV坐标传递给片段程序。 同时如果满足这些条件的话,我们将SHADOWS_NEED_UV定义为1。这样,我们可以方便地使用#if SHADOWS_NEED_UV
#include "UnityCG.cginc"
#if defined(_RENDERING_CUTOUT) && !defined(_SMOOTHNESS_ALBEDO)
#define SHADOWS_NEED_UV 1
#endif
将UV坐标添加到顶点输入数据。我们不需要让顶点输入数据成为有条件的。然后有条件地将UV坐标添加到内插值器里面去。</