mm, I am sorry, I commited three faults.
1. The normalized device coordinates are computed by dividing the result of the multiply by matProj (or so) by its w component. The raw result of the multiply is known to be in 'clip space'.
2. The y component of the result must be inversed in order to get {0, 0} at the top left corner of the screen.
3. Surprisingly, normalized device coordinates need to be divided by 4 to be in a 0<->1 range. This broke my knowledge, it has always been in a -1<->1 range...
float4 clipSpaceCoordinates = mul(float4(vecLightPos[i].xyz, 1.0f), matViewProj);
float2 normalizedProjectionCoordinatesXY = clipSpaceCoordinates.xy / clipSpaceCoordinates.w;
float2 normalizedScreenCoordinates;
normalizedScreenCoordinates.x = (1.0f + normalizedProjectionCoordinatesXY.x) / 4.0f;
normalizedScreenCoordinates.y = (1.0f - normalizedProjectionCoordinatesXY.y) / 4.0f;
float2 screenCoordinates = normalizedScreenCoordinates * vecViewPort.xy;
A PP effect needs the CHILD flag so it inherits the transformation matrices and light list from the previous stage.
Here goes an example that computes the normalized screen coordinates of a rendered entity:
#include <acknex.h>
#include <default.c>
MATERIAL *mtlNormalizedScreenCoords =
{
effect = "
float4x4 matWorldViewProj;
void VS (
in float4 inPos : POSITION,
out float4 outPos : POSITION,
out float4 outColor0 : COLOR0)
{
outPos = mul(inPos, matWorldViewProj);
outColor0.r = (1.0f + outPos.x / outPos.w) / 4.0f;
outColor0.g = (1.0f - outPos.y / outPos.w) / 4.0f;
outColor0.b = 0.0;
outColor0.a = 1.0;
}
technique
{
pass
{
VertexShader = compile vs_2_0 VS();
}
}
";
}
void main()
{
wait(1);
level_load(SPHERE_MDL);
camera->material = mtlNormalizedScreenCoords;
camera->x = -30;
while(!key_esc)
{
if(proc_status(def_move) == 0)
{
camera->pan = clamp(camera->pan + mickey.x * 0.2, -30, 30);
camera->tilt = clamp(camera->tilt + mickey.y * 0.2, -20, 20);
}
wait(1);
}
sys_exit(NULL);
}