Hello,

So I was testing my matrix class and the results look questionable and the inverted matrix isn't returning the vertex to it's original value (a seperate issue). Given a perspective projection at 45 degrees with a near of 1 and a far of 1000, the camera at the orgin looking down z and a vertext along z axis at 0, 1 and 1000, What would their resulting depths be?

Dani AI

Generated

Brief summary and focused checks based on the thread so far.

Projection is a homogeneous transform: it produces clip coordinates (Xc,Yc,Zc,Wc) that must be divided by W to get normalized device coordinates (NDC). API conventions differ: classic OpenGL NDC z is in [-1,1] (depth buffer is mapped to [0,1] after viewport transform), while Direct3D uses NDC z in [0,1]. Points at the eye position (eye‑space z = 0) give W = 0 for a perspective projection and are not projectable (division by zero). This is the core of what was pointing out.

Concrete numbers for the OP’s parameters (fov = 45°, aspect = 1, near = 1, far = 1000) assuming a GL‑style projection (camera looks down −Z):

  • eye z = −1 (near plane) → NDC z = −1 → depth buffer ≈ 0.0
  • eye z = −2 → NDC z ≈ 0.001001 → depth buffer ≈ 0.5005
  • eye z = −10 → NDC z ≈ 0.801802 → depth buffer ≈ 0.9009
  • eye z = −1000 (far plane) → NDC z = 1 → depth buffer ≈ 1.0
    These show the strong nonlinearity of depth: small changes close to the near plane produce large differences in NDC/depth.

Practical debugging checklist (grounded in the posts):

  • Confirm matrix memory/layout and multiplication order (column vs row major and whether vectors are column or row). A mismatch here causes consistent magnitude/sign errors.
  • Forward‑project simple test points (e.g., eye‑space corners and unit axes) and check their expected NDC values (near→−1, far→1 for GL). If results are off, inspect the 4th row/column entries and signs.
  • Never try to invert from post‑divide NDC values directly. To recover world/eye positions use the clip coordinates (before divide) or reconstruct clip coordinates from a known depth/W before applying (Proj×View)⁻¹. This explains the direction being right but magnitude wrong in ’s inverse test.
  • For the orthographic issue, verify that W stays 1 and that the ortho matrix’s scale/translate terms map left/right/top/bottom to ±1 exactly; a persistent ~±0.4 usually points to an indexing/order bug or an accidental divide by a non‑one W.

The Scratchapixel derivation linked earlier is a solid reference for the algebra behind these checks; use it to cross‑verify signs and denominators when re‑building the matrices.

Recommended Answers

All 10 Replies

Update:
So after a lengthy debug and fixing a few issues, I've narrowed down the bugs/ things I don't understand to the projection matrix.

Here's what I'm getting:
Looking from the origin in the vector <1,1,1> with a ratio of 1 a near of 1 and a far of 1000:
input vertex: (100, 100, 100)
restult: (0.000000, 0.000000, 171.549835)
multiplying result to inverse matrix: (0.577350, 0.577350, 0.577350) <- same direction but wrong magnitude...

So below are some assumptions and code; let me know if any of it is wrong:

P = projection matrix
M = model view matrix
Vm = vertex in "world"
Vs = screen vertex

Vs = P x M x Vm
Vm = (P x M)^-1 x Vs

        Col. Major   
      |AA BA CA DA|  
      |AB BB CB DB|  
      |AC BC CC DC| 
      |AD BD CD DD|  


   void APCamera::setPerspective(GMFloat_t fov, GMFloat_t aspect, GMFloat_t near, GMFloat_t far)
   {
      GMFloat_t difZ = near - far;

      GMFloat_t *data;

      mProjection->clear(); //set to identity matrix
      data = mProjection->getData();

      GMFloat_t v = 1.0f / tan(fov / 2.0f);

      data[_AP_MAA] = v / aspect;
      data[_AP_MBB] = v;
      data[_AP_MCC] = (far + near) / difZ;
      data[_AP_MCD] = -1.0f;
      data[_AP_MDD] = 0.0f;
      data[_AP_MDC] = 2.0f * far * near/ difZ;

      mRatio = aspect;
   }

On a first glance, i difz should be positive, so far - near, also do you have the fov in radians? Also, are data[_AP_MCC] and data[_AP_MDC] been multiplied by -1?. It could also be that the values inside the brakets do not correspond to the right matrix position, i doubt it as the direction of the resulting vector is correct (taking your word for it) and the only incosistentcy is the magnitud

here is how to derive the matrix using math
you should get familiar with how to do that so the code makes more sence

So fov is in radians and the reason data[_AP_MCC] and data[_AP_MDC] are not multiplied by -1 is because diffz is swapped.Thanks for the link, it may point to the flaw. Please let me know if anything else stands out.

If you are computing Vs from Vm, and then computing Vm back from Vs, and the two don't match, then it means that your matrix inversions are not correct. Regardless of whether you defined your matrices correctly with regard to getting a correct modelview + projection transformation, the transformation back and forth should always work if you inverted the matrices correctly.

To verify that you inverted your matrices correctly, just try to do (P x M)^-1 x P x M which should result in the identity matrix (all zero, expect all 1 on diagonal). If that's not the case, then show us your matrix inversion code and we might be able to point out the problem.

So I have already done that and I've gotten the identity matrix back. So I'm puzzled with the miss-match and shouldn't the depth be between 0 and 1 (if within the frustum)?

Also, I did it to a rotation matrix by itself, I was able to rotate a vector and undo it and multiply that inverted matrix to the original rotation matrix and get the identity back. So it's all pointing to the projection function, but nothing is standing out.

shouldn't the depth be between 0 and 1 (if within the frustum)?

The projection matrix takes the vector to the so-called "clip" coordinates, not the screen coordinates. See the last section of this complete explanation.

The depth value will only be between 0 and 1 once you have done the division by the 4th component of the vector. In other words, you start with the "world" vector:

Vm = | Xm |
     | Ym |
     | Zm |
     | 1.0|

which you then multiply by PxM, to get the "clip" vector "Vc" as this:

Vc = P x M x Vm
Vc = | Xc |
     | Yc |
     | Zc |
     | Wc |

And then, you can get the "screen" vector (where x and y are between -1 and 1, and z is from 0 to 1) as so:

Vs = | Xc / Wc |
     | Yc / Wc |
     | Zc / Wc |

You can recover Vm from Vc by the simple (P x M)^-1 transformation, but recovering Vm from Vs is a bit harder (non-linear), but not impossible either, of course.

So, that partly clears up some confusion. The one thing that has me confused is that I thought W is 1 if it's a vertex and 0 when it's a vector. Am I confusing this with something else?

So assuming that the output looks right after these adjustments, I should just be able to feed this into opengl as the projection matrix (since this is gluperspective(...))?

The one thing that has me confused is that I thought W is 1 if it's a vertex and 0 when it's a vector.

That's true for vectors in world coordinates and throughout the modelview transformation(s). However, at the last step (projection), they use the fourth component in this special way to be able to compute those normalized screen coordinates. And the projection matrix only deals with vertices anyways (no vectors), because the point of that matrix is to transform a position (vertex) from a "normal" 3D orthogonal coordinate system into the special projected coordinate system, i.e., the "clip" coordinates, which are then normalized using the fourth component.

I should just be able to feed this into opengl as the projection matrix (since this is gluperspective(...))?

Yes. The projection matrix in OpenGL is exactly that, maps from world coord. to clip coord., and the division by the fourth component will be done by OpenGL internally, after the projection matrix has been applied. So, you projection matrix should be good to use directly (e.g., with glMatrixMode(GL_PROJECTION); glLoadMatrixf(mProjection->getData());).

So it looks like getting the inverse of the perspective works, but now I'm having trouble with the Orthographic view, which is weird as it's almost a scalar matrix (assuming left,righ top,bottom are equal in magnitude). So I keep getting about +/-0.4.. on the edges no matter what I set, even if it's (-100, 100) or (-1,1). Any clue what I'm missing (I've tried both having the fourth index as 1 and as the result of the non-inverse)?

Gosh, read the links that were sent to you. It's all explained in there...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.