PDA

View Full Version : Transforming the lights position

reaktor24
09-17-2015, 10:02 AM
Not sure whether to put this in the beginners section or advanced but anyway. The problem is that I am having issues with my lighting position. First in my program loop I create a standard viewing matrix. Then after that I create the lights position vector in eye space using this method:

M_Translation.Translate(light_world_space.x, light_world_space.y, light_world_space.z);
M_ModelMatrix = M_Translation * M_Rotation;
M_LightMatrix = M_Viewing * M_ModelMatrix;
light_eye_space = M_LightMatrix * light_world_space;

Does this seem correct? I do this once per rendering frame. After this I draw a box object in the scene and from the initial point of view from the camera I can see that only one side of the box (the correct side) is lit and as the box rotates so does the lit side. In other words the light is rotating with the object.

Inside the object transformation function is this code to position and rotate the object. Into it I pass the current light position in eye space as well as the current view matrix.

void Billboard::TransformTest(mat4 viewMatrix, vec3 light_position)
{
mModelMatrix = mTranslationMatrix * mRotationMatrix;
mModelViewMatrix = viewMatrix * mModelMatrix;
mModelViewMatrix.GetMatrix(mv_Matrix);

// Now we calculate the modelview-projection matrix
mMVPMatrix = mProjectionMatrix * mModelViewMatrix;
mMVPMatrix.GetMatrix(mvp_Matrix);

// Finally we calculate the normal matrix
mNormalMatrix = mModelViewMatrix;
mNormalMatrix.InvertM();
mNormalMatrix.TransposeM();
mNormalMatrix.GetNormalMatrix(normal_Matrix);

glUniform3f(0, 1.0f, 1.0f, 1.0f); // Diffuse reflectivity
glUniform3f(1, 1.0f, 1.0f, 1.0f); // Light intensity
glUniform4f(2, light_position.x, light_position.y, light_position.z, 1.0f);
glUniformMatrix4fv(3, 1, GL_FALSE, mv_Matrix);
glUniformMatrix4fv(4, 1, GL_FALSE, mvp_Matrix);
glUniformMatrix3fv(5, 1, GL_FALSE, normal_Matrix);
glUniform1i(6, 0);
}

Any idea what I'm doing wrong? By the way as it is currently experimental code, all the Uniform locations have been numbered manually and they've all been checked and are correct.

EDIT: Ok changing 'mNormalMatrix = viewMatrix;' to 'mNormalMatrix = mModelViewMatrix;' fixed the light rotating with box problem. Now when the camera is static at the initial viewing location it does actually look correct. Moving and rotating the camera position still causes the light to move however. I wonder what I'm doing wrong. :(

GClements
09-17-2015, 10:52 AM
The problem is that I am having issues with my lighting position. First in my program loop I create a standard viewing matrix. Then after that I create the lights position vector in eye space using this method:

M_Translation.Translate(light_world_space.x, light_world_space.y, light_world_space.z);
M_ModelMatrix = M_Translation * M_Rotation;
M_LightMatrix = M_Viewing * M_ModelMatrix;
light_eye_space = M_LightMatrix * light_world_space;

Does this seem correct?

No. You're constructing a transformation which incorporates (among other components) the light's world-space position, then you're transforming the light's world-space position by it. Either a) omit M_Translation from the transformation, or b) keep M_Translation but transform the origin (0,0,0,1) rather than light_world_space.

Note that the two approaches will produce different results, because the rotation is applied before the translation. For option b), the rotation would have no effect (because you're rotating the origin about the origin), so I suspect that option a) is what you want.

reaktor24
09-17-2015, 11:17 AM
Note that the two approaches will produce different results, because the rotation is applied before the translation. For option b), the rotation would have no effect (because you're rotating the origin about the origin), so I suspect that option a) is what you want.

Hi. Thanks for the reply. I don't actually use any rotation despite the M_Rotation matrix. That is just really an identity matrix with no transformations. I tried out what you suggested and the light now stays fixed to the current camera position. This is the new light_eye_space code.

void UpdateLightPosition(void)
{
vec3 test;

M_Translation.Translate(light_world_space.x, light_world_space.y, light_world_space.z);
M_ModelMatrix = M_Translation * M_Rotation;
M_LightMatrix = M_Viewing * M_ModelMatrix;
light_eye_space = M_LightMatrix * test;
}

Oh by the way my vec3 class automatically sets the new vector to 0,0,0. So how do I now make the light remain in the same position?

EDIT:

Hmmm... I've just come across a statement which sounds like it could be my problem/solution...

http://forum.devmaster.net/t/why-point-lights-follow-my-camera/18308/17

Fixed !!! ... for some reason the constructor D3DXVECTOR4 wasn't not putting w = 1 if I was passing a D3DXVECTOR3 as its argument (therefore w was = 0 ... no translation

I don't use 4 parameters for my vectors only 3. I don't use the w component. Do you think this is where I'm going wrong? I need to have a good look at my vector and matrix code. That must be the problem.

EDIT 2:

Ok I have modified my 'Matrix * Vector' code a little bit to accomodate a fourth component:

// Multiply Operator Function 2: Matrix * Vector
vec3 mat4::operator *(vec3 u)
{
return vec3( (m[0] * u.x) + (m[1] * u.y) + (m[2] * u.z) + (m[3] * 1.0f),
(m[4] * u.x) + (m[5] * u.y) + (m[6] * u.z) + (m[7] * 1.0f),
(m[8] * u.x) + (m[9] * u.y) + (m[10] * u.z) + (m[11] * 1.0f));
}

I added m[3], m[7] and m[11] * 1.0f to the code hoping to get a correct eye_space vector but it still doesn't seem to be working. Maybe this Matrix * Vector function is wrong? I'm not sure. :(

GClements
09-17-2015, 01:20 PM
The main point is that whatever view transformation you're using to transform the object vertices into eye space, you should be using the same view transformation to transform the light position into eye space. That transformation probably shouldn't be affected by the light's position.

Typically, you have three transformations: model, view, projection. The model transformation transforms positions from object space to world space, allowing you to position and transform objects. The view transformation transforms positions from world space to object space; the view transformation is determined by the position and orientation of the observer (camera). The projection transformation transforms positions from eye space to clip space.

Legacy OpenGL combines the model and view transformations into a single transformation, as the rendering process only needs eye coordinates; it doesn't much care about how you get those. Modern OpenGL doesn't dictate any specific set of transformations, it just requires the vertex shader to emit a vertex position in clip space. However, you typically need to at least separate the projection transformation from the model-view transformation(s), as lighting calculations realistically need to be performed in an affine space (with no projective component).

When using shaders, it's perfectly feasible to perform lighting calculations in world space; it's just slightly simpler to use eye space because the eye position will always be (0,0,0,1) in eye space. The only real constraint is that all of the vectors need to be in the same coordinate system, as it's meaningless to perform arithmetic (addition, subtraction, dot/cross products) on vectors in different coordinate systems.

Having said all that, one thing stands out:

vec3 mat4::operator *(vec3 u)
{
return vec3( (m[0] * u.x) + (m[1] * u.y) + (m[2] * u.z) + (m[3] * 1.0f),
(m[4] * u.x) + (m[5] * u.y) + (m[6] * u.z) + (m[7] * 1.0f),
(m[8] * u.x) + (m[9] * u.y) + (m[10] * u.z) + (m[11] * 1.0f));
}

This is correct if either:
a) the matrix is stored in row major order, and the multiplication has the matrix on the left and a column vector on the right, yielding a column vector as the result, or
b) the matrix is stored in column-major order and the multiplication has a row vector on the left and the matrix on the right, yielding a row vector as a result.

However, OpenGL conventionally stores matrices in column-major order, with multiplications having the matrix on the left and a column vector on the right, yielding a column vector as the result, while DirectX stores matrices in row-major order, with multiplications having a row vector on the left and the matrix on the right, yielding a row vector as a result. GLSL can be made to use row-major order using a storage qualifier, or you can transpose the matrix on upload by setting the transpose parameter to GL_TRUE when calling glUniformMatrix().

IOW, the default OpenGL convention is:

[x'] [m0 m4 m8 m12] [x]
[y'] = [m1 m5 m9 m13] * [y]
[z'] [m2 m6 m10 m14] [z]
[w'] [m3 m7 m11 m15] [w]

x' = m0*x + m4*y + m8*z + m12*w
y' = m1*x + m5*y + m9*z + m13*w
z' = m2*x + m6*y + m10*z + m14*w
w' = m3*x + m7*y + m11*z + m15*w

Note that the translation component is the right-hand column: [m12,m13,m14,m15].

reaktor24
09-18-2015, 12:28 AM
Awesome, it works perfectly now! Thank you very much for the help. :)