游戏里需要一个背景,直接贴 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;
}
