5

So, I've come across some oddities between GLSL and GLM.

If I generate the following view matrix (C++):

vec3 pos(4, 1, 1);
vec3 dir(1, 0, 0);
mat4 viewMat = glm::lookAt(pos, pos+dir, vec3(0,0,1));

And then, in glsl, do:

fragColour.rgb = vec3(inverse(viewMat) * vec4(0,0,0,1)) / 4.f;

Then I expect for the screen to become pinkish-red, or (1.0,0.25,0.25). Instead, I get black.

If I do this in GLM, however:

vec3 colour = vec3(glm::inverse(viewMat) * vec4(0,0,0,1)) / 4.f;
cout << glm::to_string(colour) << endl;

I get the expect result of (1.0,0.25,0.25).

Now, if I change the viewMat to instead be (C++):

vec3 pos(4, 1, 1);
vec3 dir(1, 0.000001, 0);
mat4 viewMat = glm::lookAt(pos, pos+dir, vec3(0,0,1));

Then bam! I get (1.0,0.25,0.25) in both GLSL and GLM.

This makes no sense to me. Why does it do this? This view matrix works fine everywhere else in GLSL - I just can't invert it. This happens whenever dirY == 0.f.

Also, please suggest improvements for the question title, I'm not sure what it should be.

Edit: Also, it doesn't seem to have anything to do with lookAt's up vector (which I set to Z anyway). Even if I set up to (0,1,0), the same thing happens. Everything turns sideways, but I still can't invert the view matrix in GLSL.

Edit: Ok, so at derhass' suggestion, I tried sending the view matrix in inverted already. Bam, works perfectly. So, it seems that my GL implementation really is somehow incapable of inverting that matrix. This would have to easily be the weirdest GL bug I've ever come across. Some kind of explanation of why it's a bad idea to invert matrices in shaders would be appreciated though. EditAgain: Sending in inverted matrices throughout my engine resulted in a huge framerate boost. DEFINITELY DO THAT.

Jagoly
  • 939
  • 1
  • 8
  • 32
  • 2
    Well, as far as I can tell, this issue is totally unrealted to glm. It seems like this is just a problem with inverting in GLSL. They way your matrix is set up, it should be perfectly invertible, and numerical issues should not be a problem. This might just be an issue with your GL implementation. Also note that inverting matrices in the shader is a bad idea in most cases anyway, but it should of course work. I recommend to test this with some other GL implemenations, if possible. – derhass Apr 11 '15 at 17:02
  • @derhass Ahhh, I hadn't considered sending in the matrix already inverted. I will try that. I'll also try to see if the problem happens elsewhere too. I'm using a fairly old nvidia driver (the one in Ubuntu 14.04's repos) at the moment. – Jagoly Apr 11 '15 at 17:55
  • This was the first time I learned that GLSL now has an inverse function at all. It is definitively not a GPU friendly operation. Always be aware of the hierarchy of operations: Per draw, per vertex, per fragment. Always move stuff as low as possible. You just hit a very unlikely code path by doing inverse per vertex. Also be aware that a generic inverse is usually not needed. Most model view matrices should be "ortho normal". Where the inverse is the same as the transpose. – starmole Apr 12 '15 at 04:49
  • Heh... probably not a good time to say that I was doing it per fragment :P – Jagoly Apr 12 '15 at 04:51

1 Answers1

4

Arbitrary 4x4 matrix inversion is not a fast and safe task

For many reasons like lower FPU accuracy on GPU side and the need of many divisions during inversion (well it depends on the method of computation), and not all matrices have inverse etc (I think that is also the reason why GL has no such implementation either) ... For better image on this see Understanding 4x4 homogenous transform matrices and look for matrix_inv function there how complex the computation really is (it uses determinants). There is also GEM (Gauss elimination method) but that is not used because of its quirks and need of sorting rows ...

If the matrices are static per frame render which is usually the case it is a waste of GPU power computing it in Vertex/Fragment/Geometry shaders again and again per each Vertex/Fragment (that is why the speed boost is there).

Someone could oppose that orthogonal homogenous matrix inversion is just transposing the matrix but how the GL/GLSL could know that it deals with such matrix (the check is not that simple either) anyway in that case you can use transpose which is implemented in GLSL and should be fast (it is just reordering of elements)

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • 2
    I expect that this is the answer. Matrix inversion usually leads to numerical instability, and I'd almost always avoid inverting a matrix if I can. – Dietrich Epp Oct 08 '15 at 06:18
  • @DietrichEpp me too but in graphics especially with camera effects it cant be avoided that easily :( – Spektre Oct 08 '15 at 06:19
  • That's a common misconception, it is usually very easy to avoid. You can generate the matrix for normals and do reverse projections and the like without ever having to calculate the inverse of a general matrix. – Dietrich Epp Oct 10 '15 at 06:09