Very weird matrix behavior in GLSL

Started by
27 comments, last by rubenhak 12 years, 7 months ago
Hi Everbody,

Just came across a very weird behavior with matrix multiplication in GLSL shaders.
Trying to break this very common line of code:

gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;


into


vec4 pos = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ProjectionMatrix * pos;


but resulting gl_Position that gets calculated is different in these two samples.

This looks very weird, as matrix multiplication operation is associative (A * B) * C = A * (B * C).

Anybody came across this before? Why does this happen and is there a way to fix it?

Thanks,
Ruben
Advertisement
I had the same issue before but couldn't tell you what I did, I think I just don't use the one that works and any other calculations I have a separate variable. So if you need "pos" variable, then use it but just make sure your gl_Position is always the one that you have that works.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Matrices aren't communitive. You MUST multiply the first two together first, then multiply that result into gl_Vertex (which is acting as a column matrix in this operation). To see this for yourself, try multiplying them the original way, then do it the way you're trying to do it CPU-side, and print the results to the console. You'll see different results. Doing it by hand may also help realize what's going on.

Matrices aren't communitive. You MUST multiply the first two together first, then multiply that result into gl_Vertex (which is acting as a column matrix in this operation). To see this for yourself, try multiplying them the original way, then do it the way you're trying to do it CPU-side, and print the results to the console. You'll see different results. Doing it by hand may also help realize what's going on.


I'm not saying that matrix multiplication is commutative A * B = B * A is not true for matrices. But it is supposed to be associative, which means that for every given matrices A, B, C following statement is true: (A * B) * C = A * (B * C). In my case A can be treated as gl_ProjectionMatrix, B - as gl_ModelViewMatrix, and C - as a gl_Vertex. Quote from wiki: http://en.wikipedia.org/wiki/Matrix_multiplication#Properties

I understand that there is something happening on the GPU side, but from math perspective, no matter what is the sequence of operations, result should be the same. I just did a test with Matlab with various random matrices/vectors and results were same.
Try:

vec4 pos = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ProjectionMatrix * vec4(pos.xyz, 1.0);

Thats the only thing I can think of is something with the w component. Regardless if you need:

vec4 pos = gl_ModelViewMatrix * gl_Vertex;
//Do some calculations with pos variable
gl_Position = gl_ProjectionMatrix * pos;

You would have the same exact amount of lines of code by doing:

vec4 pos = gl_ModelViewMatrix * gl_Vertex;
//Do some calculations with pos variable
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

so just do that anyway.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal


Try:

vec4 pos = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ProjectionMatrix * vec4(pos.xyz, 1.0);

Thats the only thing I can think of is something with the w component. Regardless if you need:

vec4 pos = gl_ModelViewMatrix * gl_Vertex;
//Do some calculations with pos variable
gl_Position = gl_ProjectionMatrix * pos;

You would have the same exact amount of lines of code by doing:

vec4 pos = gl_ModelViewMatrix * gl_Vertex;
//Do some calculations with pos variable
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

so just do that anyway.




Trick with setting w = 1.0 does not make any difference. I know that I can use gl_ModelViewProjectionMatrix instead, but that makes it very weird and I do not have any confidence when using matrix multiplication any more.... :(


Trying to break this very common line of code:
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;into vec4 pos = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ProjectionMatrix * pos;
Shouldn't you be concatenating the matrices, and then using the result to transform the position?vec4 modelViewProj = gl_ProjectionMatrix * gl_ModelViewMatrix;
gl_Position = modelViewProj * gl_Vertex;
[edit]actually, no, I don't see a problem with your method... transforming a point into view-space, and then projecting it should work too... :/

[quote name='rubenhak' timestamp='1315637398' post='4859902']Trying to break this very common line of code:
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;into vec4 pos = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ProjectionMatrix * pos;
Shouldn't you be concatenating the matrices, and then using the result to transform the position?vec4 modelViewProj = gl_ProjectionMatrix * gl_ModelViewMatrix;
gl_Position = modelViewProj * gl_Vertex;
[edit]actually, no, I don't see a problem with your method... transforming a point into view-space, and then projecting it should work too... :/
[/quote]

That could be another way of doing, but still cannot see a reason why doing my way does not work...
This looks very weird, as matrix multiplication operation is associative (A * B) * C = A * (B * C).

Except that they are talking about matrix multiplcation. That is, C is not a vector when they write that.

The meaning is that (A * B) * C will create the same matrix as A * (B * C).
Using (gl_ModelViewProjectionMatrix * gl_Vertex) is the same as using (gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex) because the result of (gl_ProjectionMatrix * gl_ModelViewMatrix) is a matrix equal to gl_ModelViewProjectionMatrix.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid


[quote name='rubenhak' timestamp='1315637398' post='4859902']This looks very weird, as matrix multiplication operation is associative (A * B) * C = A * (B * C).

Except that they are talking about matrix multiplcation. That is, C is not a vector when they write that.

The meaning is that (A * B) * C will create the same matrix as A * (B * C).
Using (gl_ModelViewProjectionMatrix * gl_Vertex) is the same as using (gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex) because the result of (gl_ProjectionMatrix * gl_ModelViewMatrix) is a matrix equal to gl_ModelViewProjectionMatrix.


L. Spiro
[/quote]

Vector is a custom case of a m-by-n matrix where m (or n) is equal to 1.

I need to calculate value of pos:
pos = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;


I just want to do it differently:
p1 = gl_ModelViewMatrix * gl_Vertex;
p2 = gl_ProjectionMatrix * p1;


resulting p2 is not equal to pos. Could you explain me why? Manually I substitute any random values into gl_ProjectionMatrix, gl_ModelViewMatrix and gl_Vertex values and calculate pos and p2 manually and get equal results. However, in GLSL getting different values. Any ideas why?

This topic is closed to new replies.

Advertisement