来自:DX Samples: PIXGameDebugging.fx
包括两个部分:
1. 棋盘上所看到的水波花纹
2. 纵向的光纹
1. 使用32张现成的腐蚀纹理(caustic),来做水波变化的动态效果
2. 将光线、腐蚀因子、物体颜色,三者相乘
1. 需要输入时间;
2. 预先加载所有纹理,利用时间(或其他)计算选取哪张腐蚀纹理,并设置。
VS_OUT CausticVS(VS_IN IN) // vertex shader
{
VS_OUT OUT;
float2x2 rotation = {COS_0_15F, -SIN_0_15F, SIN_0_15F, COS_0_15F}; // 一个常数
float4 viewPosition = mul(IN.Position, WorldView); // 在观察空间的位置。【位置 * ( worldTrans * ViewTrans )】
float3 viewNormal = normalize(mul(IN.Normal, WorldViewIT)); // 把法线转换到观察空间。【法线 / ( worldTrans * ViewTrans )】【这里为啥是除法,不懂】
OUT.Position = mul(IN.Position, WorldViewProj); // 输出位置 = 输入位置变换到投影空间的结果
OUT.Color = Light1Ambient + dot(viewNormal, Light1Dir); // 输出颜色 = 环境光 + 漫反射光(此处没有使用漫反射系数)
OUT.TexCoord0 = IN.TexCoord; // 输出纹理坐标0 = 原纹理坐标0,将会被用作获取物体本身的纹理
OUT.TexCoord1.xy = mul(viewPosition.xz, rotation); // 输出纹理坐标1 = 观察空间的位置 * 一个固定的旋转,将会被用作获取腐蚀纹理
OUT.Fog = FogData.z * (FogData.y - length(viewPosition.xyz)); // 对观察空间位置到原点的距离,利用一个输入的变量进行线性变换,得到最终的雾效大小
return OUT;
}
float4 CausticPS(VS_OUT IN) : COLOR // pixel shader
{
float2 movement = IN.TexCoord1.xy;
movement.x = movement.x + cos(Time * 0.2f) * 0.3f; // 对vs中计算的“表征观察空间中的位置”的二维向量,加上一个时间相位
movement.y = movement.y + sin(Time * 0.3f) * 0.2f;
float3 color = IN.Color.rgb * tex2D(CausticTextureSampler, movement.xy * 0.9f); // 将上述随时间和空间变化的固定值,作为纹理坐标,索引到腐蚀纹理中,然后与原有光效颜色,使用乘法进行混合
color = color * tex2D(MeshTextureSampler, IN.TexCoord0.xy); // 将物体本身颜色与水波花纹相乘,也使用乘法
return float4(color, 1.0f);
}
LightShaftVertex g_LightVertices[] = // triangle list for lightshafts
{
{ -1.0f, -1.1f, 0.0f, 0x0066ccff },
{ -1.0f, 1.5f, 0.0f, 0x1166ccff }, // x, y, z, color
{ 1.0f, -1.10f, 0.0f, 0x0066ccff },
{ -1.0f, 1.5f, 0.0f, 0x1166ccff },
{ 1.0f, 1.5f, 0.0f, 0x1166ccff },
{ 1.0f, -1.1f, 0.0f, 0x0066ccff },
};
VS_LIGHTSHAFT_OUT LightShaftAlternateVS(VS_LIGHTSHAFT_IN IN) // vertex shader
{
VS_LIGHTSHAFT_OUT OUT;
OUT.Position = IN.Position; // 输出位置依然是输入位置,因为输入已经被当做是屏幕位置了
OUT.Position.z = OUT.Position.z + LightShaftZ; // 由CPU控制z值平滑变化,防止重叠;在多层layer的情况下,z值还会有一个平滑的变化,从而也使得重叠显得更为有质感
OUT.Color = IN.Color; // 颜色固定
OUT.TexCoord0.xy = OUT.Position.xz*0.9f; // 把屏幕坐标的x和z作为输出的纹理坐标,亦即其z值不变【不知道为什么要带一个缩放】
return OUT;
}
float4 LightShaftPS(VS_LIGHTSHAFT_OUT IN) : COLOR // pixel shader
{
float3 color = IN.Color.rgb * tex2D(CausticTextureSampler, IN.TexCoord0.xy); // 根据上边生成出的uv坐标,在腐蚀纹理中得到颜色。将其与原有颜色相乘作为最终颜色
return float4(color, IN.Color.a); // 注:本效果框架中alpha混合模式为src=srcalpha, dest=one,因而对最终颜色总是加强的
}
VS_LIGHTSHAFT_OUT LightShaftVS(VS_LIGHTSHAFT_IN IN) // vertex shader
{
VS_LIGHTSHAFT_OUT OUT;
float2x2 rotation = {COS_0_15F, -SIN_0_15F, SIN_0_15F, COS_0_15F}; // 固定的旋转
OUT.Position = IN.Position; // 输出的位置为输入的位置(屏幕位置)
float4 movement = IN.Position;
movement.x = movement.x + cos(Time * 0.2f) * 0.3f; // 增加时间相位
movement.z = movement.z + sin(Time * 0.3f) * 0.2f;
OUT.Position.z = OUT.Position.z + LightShaftZ; // z值增加一个可控变量。该值在多层layer时平滑递减
OUT.Color = IN.Color;
OUT.Color.a = LightShaftAlpha; // 颜色为本身颜色,alpha值为程序控制,为固定值
OUT.TexCoord0.xy = mul(OUT.Position.xz, rotation) + movement.xz; // 原位置的旋转 + 原位置 + 时间相位
OUT.TexCoord0.xy = OUT.TexCoord0.xy * 0.9f + 1.0f / (1.0f - OUT.Position.z); // 缩放后加上一个外部控制的变量LightShaftZ 【不知道为什么要加这个变量】
return OUT;
}
float4 LightShaftPS(VS_LIGHTSHAFT_OUT IN) : COLOR // pixel shader
{
float3 color = IN.Color.rgb * tex2D(CausticTextureSampler, IN.TexCoord0.xy); // 同前
return float4(color, IN.Color.a);
}