Math for computing relative sun direction

Started by
19 comments, last by Meltac 11 years, 5 months ago
isnt this function what are you looking for? This rotates (x,y,z) about the axis (u,v,w) by the angle ?.

f(x,y,z,u,v,w,?) =

ArbitraryAxisRotation13x.png
Advertisement
Ok, so far transformation and rotation worked more or less. Now I'm having an issue with this transformation:



// Transform sun position to screen space
SunPos = mul( SunPos, ViewProj );


float4x4 TexAdj = { 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f };

SunPos = mul( SunPos, TexAdj );


// Calculate vector from pixel to light source in screen space.
float2 deltaTex = (TexPos - SunPos);



This works well as long as the sun is near the center of the screen, but the more peripheral it gets (i.e. the nearer to the screen's border it is located) the less accurate the transformation seems to be: The computed sun position in screen space is "too much centered" in comparison to the real visual sun location on the screen.

It seems to me like an issue of linear versus radial transformation, so that the above formula does not seem to take into account that the field of view of the camera is not linear but radial, meaning that when turning the camera for example to the left so that the visible sun moves to the right within the screen (if it was in its center), this "linear" movement needs to take the camera rotation (=radial movement) into account - what seems not to be the case with the above formula.

My problem is that I don't understand the respective math well enough to figure out how to fix this. Can you help me here? What formula needs to be applied to correct this?
Anyone please?
Wouldn't you want to divide-by-w after transforming by your ViewProj, assuming that it contains a perspective projection?

EDIT: nevermind, I realized that the code is from someone else and it's probably not the code that you're using.

EDIT: nevermind, I realized that the code is from someone else and it's probably not the code that you're using.


I'm basically using SIIYA's code:



// Transform sun position to screen space
SunPos = mul( SunPos, ViewProj );


float4x4 TexAdj = { 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f };

SunPos = mul( SunPos, TexAdj );


// Calculate vector from pixel to light source in screen space.
float2 deltaTex = (TexPos - SunPos);



However I've also tried a few other transformations and projection matrices, as well as building my own. The overall result is always the same: The calculated sun position is more or less correct as long as near the screen center, but when moving further to the left or right, it becomes worse. The calculated position then is too much left or right, but when the sun moves towards the left or right border of the screen, the calcuation is not enough left or right.

So there must by some math function responsible for this behavior. If I'd know that function I could correct the calculation. I've tried polynomial functions with pow(...) but that seemed not to be the right one. Might it be some sinus or cosinus function that I'm needing in this case? Or any other correction algorithm?
I'm still struggling... I guess the projection of the sun coords from 3D to 2D (world to screen space) is not yet done correctly.

As said, I'm using SIIYA's approach:



// Transform sun position to screen space
SunPos = mul( SunPos, ViewProj );


float4x4 TexAdj = { 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f };

SunPos = mul( SunPos, TexAdj );


// Calculate vector from pixel to light source in screen space.
float2 deltaTex = (TexPos - SunPos);



Might the TexAdj matrix be wrong in my case? Were do these values come from? Also, I don't see any relation to the FOV, isn't that important here?

BTW; a divide-by-w is most propably not possible here (if even required) because all position values I'm getting from the engine are either only float3, or have w = 0.
Still nobody who could shed a little light on that issue?
As MJP correctly pointed out, the homogenous clip space coordinates need to be divided by w. So the correct code would look like this:


// Transform sun position to screen space
SunPos = mul( SunPos, ViewProj );

SunPos /= SunPos.w;

float4x4 TexAdj = { 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f };

SunPos = mul( SunPos, TexAdj );


// Calculate vector from pixel to light source in screen space.
float2 deltaTex = (TexPos - SunPos);


If your world space SunPos isn't (x, y, z, 1) you need to set w to 1 before the projection.

When I did this, I simply drew the sun on the screen to check if it aligns with the already drawn sun:

float3 color = distance(TexPos, SunPos) < 0.005 ? float3(1, 0, 0) : tex2D(sampler0, input.texCoord).rgb;

As MJP correctly pointed out, the homogenous clip space coordinates need to be divided by w. So the correct code would look like this:

If your world space SunPos isn't (x, y, z, 1) you need to set w to 1 before the projection.


Thanks, but the SunPos that I'm getting from the engine is a float3, so I don't have a w here! Also, float4(SunPos, 1) obviously doesn't change a thing.


When I did this, I simply drew the sun on the screen to check if it aligns with the already drawn sun:

float3 color = distance(TexPos, SunPos) < 0.005 ? float3(1, 0, 0) : tex2D(sampler0, input.texCoord).rgb;


I don't want to draw the sun, but render sun shafts coming from the correct direction where the sun is rendered by the engine is in screen space.

Thanks, but the SunPos that I'm getting from the engine is a float3, so I don't have a w here! Also, float4(SunPos, 1) obviously doesn't change a thing.

It does, because the ViewProj matrix needs homogeneous coordinates for it to work correctly. The resulting vector will have a w-component that is essential for the projection to work. Here's the code:


float4 homogeneousSunPos = float4(SunPos, 1);

// Transform sun position to screen space
homogeneousSunPos = mul( homogeneousSunPos, ViewProj );

homogeneousSunPos /= homogeneousSunPos.w;

float4x4 TexAdj = { 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f };

homogeneousSunPos = mul( homogeneousSunPos, TexAdj );

// Calculate vector from pixel to light source in screen space.
float2 deltaTex = (TexPos - homogeneousSunPos);



I don't want to draw the sun, but render sun shafts coming from the correct direction where the sun is rendered by the engine is in screen space.

It's just easier to tell whether the projected sun position works... Simply for debugging purposes...

This topic is closed to new replies.

Advertisement