When programing in water rendering, I've met a perplexing problem about projected texture coordinate. I render scene to a texture, then project to a surface to simulate water. So need generating texture coordinates for the surface in real time, I use vertex shader to do this (and no use pixel shader in whole water rendering).
First, My vs codes is:
vs.1.0
m4x4 r0, v0, c4 //v0 - Vertex Position
//c4-7 - Composite World-View-Projection Matrix
mov oPos,r0
//c0 - { 0.0, 0.5, 1.0, 2.0}
add r0.x, r0.w, r0.x // r0.x = (pos.w + pos.x) * 0.5
mul r0.x, r0.x, c0.y
add r0.y, r0.w, -r0.y // r0.y = (pos.w - pos.y ) * 0.5
mul r0.y, r0.y, c0.y
rcp r2.w, r0.w // r0.xyz/=pos.w
mul r0.xyz, r0, r2.w
mov oT1, r0
mov oT3, r0
and texture stage states is:
// stage1
ColorOp[1] = SelectArg1;
ColorArg1[1] = Texture;
...
// stage3
ColorOp[3] = BlendDiffuseAlpha;
ColorArg1[3] = Texture;
ColorArg2[3] = Current;
These codes gets a halfway success: when camera is faraway to water surface, everything looks well; but if camera close to water, the projected texture looks distorted and chapped. see below screenshot:
After many attempts, I've found the solution finally: remove the w-division from
vertex shader, and do the division by setting TextureStageState - D3DTSS_TEXTURETRANSFORMFLAGS. So the modified vs codes is:
vs.1.0
m4x4 r0, v0, c4 //v0 - Vertex Position
//c4-7 - Composite World-View-Projection Matrix
mov oPos,r0
//c0 - { 0.0, 0.5, 1.0, 2.0}
add r0.x, r0.w, r0.x // r0.x = (pos.w + pos.x) * 0.5
mul r0.x, r0.x, c0.y
add r0.y, r0.w, -r0.y // r0.y = (pos.w - pos.y ) * 0.5
mul r0.y, r0.y, c0.y
mov oT1, r0
mov oT3, r0
and modified texture stage states is:
// stage1
ColorOp[1] = SelectArg1;
ColorArg1[1] = Texture;
TextureTransformFlags[1] = Count3|Projected;
...
// stage3
ColorOp[3] = BlendDiffuseAlpha;
ColorArg1[3] = Texture;
ColorArg2[3] = Current;
TextureTransformFlags[3] = Count3|Projected;
This time the result is satisfying, the water looks well from anywhere:
So I have a question: why do the w-division in vertex shader cause the distortion? (Is it perspective-correction correlative? Is there a method to disable perspective-correction in D3d 8.1?)