shader学习笔记 - 水底效果

shader学习笔记 - 水底效果_第1张图片
来自:DX Samples: PIXGameDebugging.fx

包括两个部分:
1. 棋盘上所看到的水波花纹
2. 纵向的光纹

水波花纹

关键:

1. 使用32张现成的腐蚀纹理(caustic),来做水波变化的动态效果
2. 将光线、腐蚀因子、物体颜色,三者相乘

CPU部分:

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);
}

纵向光纹 - 第一种

shader学习笔记 - 水底效果_第2张图片

关键:

  1. 在CPU中多次渲染,来控制光线厚度;
  2. 使用一个两个三角形组成的长方形,来作为渲染对象,以此在ps中遍历屏幕;
  3. 使用上述长方形本身的颜色的alpha值,来控制在屏幕上的透明变化;

CPU部分:

  1. 按照light layer的值进行多次渲染;
  2. 制作一个由两个三角形组成的长方形的模型,作为渲染对象【不知道为什么要用1.1和1.5】;
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,因而对最终颜色总是加强的
}

纵向光纹 - 第二种

shader学习笔记 - 水底效果_第3张图片

关键:

  1. 在第一种的基础上,修改alpha值为一个程序输入的固定值,从而造成在y方向上光纹透明度不变

CPU部分:

效果部分:

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);
}

你可能感兴趣的:(shader)