游戏里需要一个背景,直接贴 2d 图片的话显得有些单调了,打算做个动态的背景。用水面的话视野比较广阔,感觉比较合适。
因为游戏是直接用 dx 写的,所以水面的实现也自然是写 shader 来完成了。

基本的原理就是通过 PSshader 来做 uv 动画,改变像素和贴图间的映射,从而模拟出水面波动的效果。因为也没做光照之类的处理,效果就差了些。

水面

直接附上 shader 代码,核心就是两条三角函数变换的语句了。

cbuffer ConstantBuffer : register(b0)
{
    matrix World;
    matrix View;
    matrix Projection;
    float4 vMeshColor;
    float2 param;
}

Texture2D txDiffuse    : register(t0);
Texture2D txAnother    : register(t1);
Texture2D txMask       : register(t2);
SamplerState samLinear : register(s0);


struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD0;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD0;
};

PS_INPUT VS(VS_INPUT input)
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul(input.Pos, World);
    output.Pos = mul(output.Pos, View);
    output.Pos = mul(output.Pos, Projection);    
    output.Tex = input.Tex;
    return output;
}

float4 PS(PS_INPUT input) : SV_Target
{
    float4 another = txAnother.Sample(samLinear, input.Tex);
    float4 alpha = txMask.Sample(samLinear, input.Tex);
    
    // 更新像素点的 uv 偏移,相当于点在做圆周运动
    // param.x 是以秒为单位的时间
    float2 bg = input.Tex;
    bg.x += sin(param.x + bg.x * 15) * 0.01;
    bg.y += cos(param.x + 0.003 + bg.y * 15) * 0.01;

    float4 color = txDiffuse.Sample(samLinear, bg) * vMeshColor;
    float4 finanl = color * (1.0f - alpha) + alpha * another;
    float4 blend = saturate(finanl);
    return color;
}