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