Well, here's the code that actually works, if anybody is curious. I think this is about as minimal as I could get it:
Vertex program:
Code: Select all
TEMP screenUVs; # uv's in screen space
MOV screenUVs, pos;
PARAM scaleFlipReflection = { 0.5, -0.5, 1.0, 1.0 }; # negative value is because we need to flip on Y.
MUL screenUVs, screenUVs, scaleFlipReflection;
MOV result.texcoord[0], screenUVs;
Fragment program:
Code: Select all
TEMP recipW;
TEMP reflectionUV;
RCP recipW, fragment.texcoord[0].w;
MAD reflectionUV, recipW, fragment.texcoord[0], 0.5; # scale and center the reflection texture
TEX endColor, reflectionUV, texture, 2D;
One thing I find strange is that I can use either of these:
TEMP recipPosW; # 1 / vertex.position.w
RCP recipPosW, vertex.position.w;
MUL screenUVs, recipPosW, pos;
or
MOV screenUVs, pos;
and the result appears to be the same. I even tried making the W component of recipPosW 1 so it wouldn't scale the W component as well, but it didn't seem to make a difference.
I thought maybe I could reduce the fragment program by 1 instruction and move the RCP to the vertex program, storing 1/w in the w component instead of w:
Added to vertex program:
Code: Select all
TEMP recipTexW;
RCP recipTexW, screenUVs.w;
MOV result.texcoord[0].w, recipTexW.w;
Fragment program, changed:
RCP recipW, fragment.texcoord[0].w;
to:
MOV recipW, fragment.texcoord[0].w;
The result:
Not as messed up as trying to do the full calculation at the vertex level, but there still ended up being a lot of distortion. I guess, like you said, "depth distorts". There must be some kind of special interpolation going on for the w component that just will not work with a reciprocal.
Actually, when I clean up all the temp vars that aren't necessary anymore, this is the most optimal vertex prog:
Code: Select all
PARAM scaleFlipReflection = { 0.5, -0.5, 1.0, 1.0 }; # negative value is because we need to flip on Y.
MUL result.texcoord[0], pos, scaleFlipReflection;