|
vecLightViewPos question
#480006
05/12/20 23:29
05/12/20 23:29
|
Joined: May 2009
Posts: 5,370 Caucasus
3run
OP
Senior Expert
|
OP
Senior Expert
Joined: May 2009
Posts: 5,370
Caucasus
|
Hi!
I would like to know more about vecLightViewPos[8], manual just doesn't say anything about it... I'm trying to get the position of each light via pp shader, and thought, that I need to get position relative to the view coordinates, so that's why I'm trying to learn more about vecLightViewPos. I thought that it's float3 with x, y being the screen coordinates and z the lightrange... but this doesn't work, then I tried to use it as a float4 with .w being the lightrange (as for vecLightPos), but this doesn't work either... What would you guys suggest, what am I doing wrong?
Last edited by 3run; 05/13/20 19:55.
|
|
|
Re: vecLightViewPos question
[Re: 3run]
#480008
05/13/20 08:29
05/13/20 08:29
|
Joined: Jun 2007
Posts: 1,337 Hiporope and its pain
txesmi
Serious User
|
Serious User
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
|
Hi, 'view space' is a Carthesian three dimensional coordinate system like 'world space', but aligned with the position and rotation of a camera. In d3d9, the X axe goes forward on the view direction, Y up, and Z to the left.
worldSpacePos * matView -> viewSpacePos // it had an error, fixed. viewSpacePos * matViewInv -> worldSpacePos
Last edited by txesmi; 05/13/20 11:58. Reason: ERROR!!!!
|
|
|
Re: vecLightViewPos question
[Re: 3run]
#480010
05/13/20 10:42
05/13/20 10:42
|
Joined: May 2009
Posts: 5,370 Caucasus
3run
OP
Senior Expert
|
OP
Senior Expert
Joined: May 2009
Posts: 5,370
Caucasus
|
In this case, I should get lightrange from the vecLightPos.w. As for the position of the light in screen coordinates, vecLightViewPos doesn't help, I guess I need to convert vecLightPos.xyz to screen pos? Already tried oPos = mul(iPos,matWorldViewProj); but that didn't help either. Edit: I found this algorithm to convert from cartesian to screen:
screenX = cartX + screen_width/2
screenY = screen_height/2 - cartY
// converted it into
float pos_x = vecLightViewPos[i].x + vecViewPort.x / 2;
float pos_y = vecViewPort.y / 2 - vecLightViewPos[i].y;
It already looks a bit more closer to what I want to archive, but it looks like positions aren't correct when close to the light sources... But on distance it's almost what I want to archive.
Last edited by 3run; 05/13/20 10:54.
|
|
|
Re: vecLightViewPos question
[Re: 3run]
#480014
05/13/20 12:33
05/13/20 12:33
|
Joined: Jun 2007
Posts: 1,337 Hiporope and its pain
txesmi
Serious User
|
Serious User
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
|
The only way to get correct screen coordinates is throgh the normalized device coordinate system (NDC) which can be computed by multiplying object space coordinates by matWorldViewProj, or world space coordinates by matViewProj, or view space coordinates by matProj, since the projection of the camera is determinant.
float2 normalizedProjectionCoordinatesXY = mul(float4(vecLightPos[i].xyz, 1.0f), matViewProj).xy; // range: -1 <-> 1
// or, with the same price and same result:
// float2 normalizedProjectionCoordinatesXY = mul(float4(vecLightViewPos[i].xyz, 1.0f), matProj).xy;
float2 screenCoordinates = (0.5f + normalizedProjectionCoordinatesXY * 0.5f) * vecViewport.xy; // range: 0 <-> screen_size - 1
As far as I understand, the radius of the light can't be directly tranformed to screen cordinates as easy as common coordinates. It will need to compute a position in the desired coordinate system, transform it to NDC, compute the resulting radius of the projection and use it with light position screen coordinates to draw the projected circle of the light sphere.
float2 normalizedProjectionCoordinatesXY = mul(float4(vecLightViewPos[i].xyz, 1.0f), matProj).xy;
float normalizedProjectionCoordinatesOfOuterPointOfLightSphereX = mul(float4(vecLightViewPos[i].xy, vecLightViewPos[i].z - vecLightViewPos[i].w, 1.0f), matProj).x ; // doing the same in world space would need far more computations
float projectedLightRadiusInScreenPixels = vecViewPort.x * (normalizedProjectionCoordinatesOfOuterPointOfLightSphereX - normalizedProjectionCoordinatesXY.x) / 2.0f;
Notice that in order to compute the projected light radius, the original light radius is subtracted to the view space Z coordinate of the light, which is the inversed X coordinate in screen space. View space YZ plane is parallel to the camera projection plane, so it is proportional to the distance according to the projection. Salud! DISCLAIMER: I did not test any of the code above, I might had failed but I am pretty sure it is correct.
|
|
|
Re: vecLightViewPos question
[Re: 3run]
#480016
05/13/20 13:36
05/13/20 13:36
|
Joined: May 2009
Posts: 5,370 Caucasus
3run
OP
Senior Expert
|
OP
Senior Expert
Joined: May 2009
Posts: 5,370
Caucasus
|
I tried out the following:
float2 normalizedProjectionCoordinatesXY = mul(float4(vecLightViewPos[i].xyz, 1.0f), matProj).xy;
float normalizedProjectionCoordinatesOfOuterPointOfLightSphereX = mul(float4(vecLightViewPos[i].xy, vecLightViewPos[i].z - vecLightViewPos[i].w, 1.0f), matProj).x;
float projectedLightRadiusInScreenPixels = vecViewPort.x * (normalizedProjectionCoordinatesOfOuterPointOfLightSphereX - normalizedProjectionCoordinatesXY.x) / 2.0f;
float2 screenCoordinates = (0.5f + normalizedProjectionCoordinatesXY * 0.5f) * vecViewPort.xy;
So I set position to screenCoordinates.xy and range to projectedLightRadiusInScreenPixels, but screen is plain dark Tried out matWorldViewProj and matViewProj instead of matProj, but no changes... Also, does vecLightViewPos[i].w contain lightrange? Edit: this is what I want to archive at the end
Last edited by 3run; 05/13/20 15:34.
|
|
|
Re: vecLightViewPos question
[Re: 3run]
#480020
05/13/20 16:44
05/13/20 16:44
|
Joined: Jun 2007
Posts: 1,337 Hiporope and its pain
txesmi
Serious User
|
Serious User
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
|
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);
}
Last edited by txesmi; 05/13/20 18:30. Reason: error fix
|
|
|
Re: vecLightViewPos question
[Re: 3run]
#480021
05/13/20 18:21
05/13/20 18:21
|
Joined: May 2009
Posts: 5,370 Caucasus
3run
OP
Senior Expert
|
OP
Senior Expert
Joined: May 2009
Posts: 5,370
Caucasus
|
Thank you for examples, txesmi! I have a question.
float3 clipSpaceCoordinates = mul(float4(vecLightPos[i].xyz, 1.0f), matViewProj).xy;
float2 normalizedProjectionCoordinatesXY = clipSpaceCoordinates.xy / clipSpaceCoordinates.w;
clipSpaceCoordinates is a float3, but you use it's clipSpaceCoordinates .w in normalizedProjectionCoordinatesXY calculation. Also, in clipSpaceCoordinates itself you only set .xy while calculating it. So in order to compile, I've changed float3 clipSpaceCoordinates to float4, but it doesn't work. Also, I've set CHILD flag for the pp view. EDIT: Also in normalizedScreenCoordinates.y = (1.0f - normalizedProjectionCoordinatesXY.y) / 4.0f; You used normalizedProjectionCoordinatesXY.x Instead of Y is that intentional? EDIT2: ok, I see that you fixed the previous post, but it still doesn't work for some reason... This is the code I tried out (tried both vecLightViewPos and vecLightPos).
float4 clipSpaceCoordinates = mul(float4(vecLightViewPos[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;
float normalizedProjectionCoordinatesOfOuterPointOfLightSphereX = mul(float4(vecLightViewPos[i].xy, vecLightViewPos[i].z - vecLightViewPos[i].w, 1.0f), matProj).x;
float projectedLightRadiusInScreenPixels = vecViewPort.x * (normalizedProjectionCoordinatesOfOuterPointOfLightSphereX - normalizedProjectionCoordinatesXY.x) / 2.0f;
Last edited by 3run; 05/13/20 19:55.
|
|
|
|