2

Meaning at this point the projection has already been done. This article gives us the projection matrix used by OpenGL, and the factor that affect the z-coordinate of a point is the row:

[ 0 0 -(f+n)/(f-n) -2fn/(f-n) ]

Note, this matrix is computed to make the ‘pyramidal’ frustum to a unit cube. Meaning the z-coordinate has also been mapped to [0,1] after this matrix is applied.

Then, the author in the depth value precision chapter tells us: These z-values in view space can be any values between frustum’s near and far plane and we need some way to transform them to [0,1]. The question is why at this point, when we had already mapped it while applying the projection matrix.

Also, he says: a linear depth buffer like this: F_depth=z-near/(far-near) is never used, for correct projection properties a non-linear depth equation is used:

F_depth= (1/z- 1/near)/(1/far - 1/near)

But, as we have seen, z is mapped within range using:

[ 0 0 -(f+n)/(f-n) -2fn/(f-n) ]

Which appears to be linear.

All these contradicting statements are making me really confused on when is the depth for fragments calculated and compared,and what is the equation actually used to compute this. In my understanding nothing more for depth should be calculated after the OpenGL projection matrix is applied, but after reading this I’m really confused. Any clarifications?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
horxCoder
  • 165
  • 8

1 Answers1

1

At perspective projection the depth is not linear, because of the perspective divide.

When a vertex coordinate is transformed by the projection matrix then the clip space coordinate is computed. The clip space coordinate is a Homogeneous coordinate. Now all the geometry which is not in clip space (in the Viewing frustum) is clipped. The clipping rule is:

-w <=  x, y, z  <= w

After that the normalized device space coordinate is computed by dividing the x, y, z components by the w component (Perspective divide). NDC are Cartesian coordinates and the normalized device space is a unique cube with the left, bottom, near of (-1, -1, -1) and right, top, far of (1, 1, 1). All the geometry in the cube is projected on the 2 dimensional viewport.

Note, after the homogeneous vertex coordinate is multiplied by the perspective projection matrix (clip space) the z component is "linear" but it is not in range [-1, 1]. After clipping and perspective divide, the z coordinate is in range [-1, 1] (NDC), but it is no longer "linear".

The depth buffer can store values in range [0, 1]. Hence the z component of the normalized device space has to be mapped from [-1.0, 1.0] to [0.0, 1.0].


At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).

A perspective projection matrix can be defined by a frustum.
The distances left, right, bottom and top, are the distances from the center of the view to the side faces of the frustum, on the near plane. near and far specify the distances to the near and far plane of the frustum.

r = right, l = left, b = bottom, t = top, n = near, f = far

x:    2*n/(r-l)      0              0                0
y:    0              2*n/(t-b)      0                0
z:    (r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1
t:    0              0              -2*f*n/(f-n)     0

If the projection is symmetrical and the line of sight is the axis of symmetry of the frustum, the matrix can be simplified:

a  = w / h
ta = tan( fov_y / 2 );

2 * n / (r-l) = 1 / (ta * a)
2 * n / (t-b) = 1 / ta
(r+l)/(r-l)   = 0
(t+b)/(t-b)   = 0

The symmetrically perspective projection matrix is:

x:    1/(ta*a)  0      0              0
y:    0         1/ta   0              0
z:    0         0     -(f+n)/(f-n)   -1
t:    0         0     -2*f*n/(f-n)    0

See also

What exactly are eye space coordinates?

How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • but then the `F_depth` formula must have some sort of mistake, consider near, far > 1; because, |1/near| < 1 always but |1/z| >= 1 always, and |(1/far - 1/near)| < 1 always, which means F_depth > 1 always ? – horxCoder Jul 25 '20 at 06:24
  • @horxCoder No, this is not the complete formula. The projection matrix computes the clip space coordinate (4 components). The components of the clip space are divided by the w component. The projection matrix transforms from view space to clip space. In common view space is a right handed system, but clip space and (NDC) is a left handed system. The projection matrix mirrors the z axis. – Rabbid76 Jul 25 '20 at 06:29
  • @horxCoder `[ 0 0 -(f+n)/(f-n) -2fn/(f-n) ] ` dos not define a mapping. This is the 3rd row of the 4x4 perspective projection matrix. – Rabbid76 Jul 25 '20 at 06:41
  • what do you mean by, " doesn't define a mapping"? It maps the z coord from sth to [-1,1], doesn't it? – horxCoder Jul 25 '20 at 08:19
  • @horxCoder No it does not. Please read the answer. It's the 3rd row of the matrix perspective projection matrix. The homogeneous vertex coordinate is multiplied by the matrix. The result is the homogeneous clip space coordinate. In clip space the z component is "linear" but it is not in range [-1, 1]. After the perspective divide, the z coordinate is in range [-1, 1] (NDC), but it is not longer "linear". – Rabbid76 Jul 25 '20 at 12:48
  • @horxCoder Sorry, but I don't know what you mean. Anyway the condition is correct. The clip space coordinates system is a left handed system. In compare to view space the z axis is mirrored. In view space the z axis points out of the viewport, because the view space coordinate system is a right handed system. See [What exactly are eye space coordinates?](https://stackoverflow.com/questions/15588860/what-exactly-are-eye-space-coordinates/61537327#61537327) – Rabbid76 Jul 25 '20 at 14:27
  • and the clip coordinates seem to themself be in [-1,1] then why do you say the division by `w` is converting them to NDC? – horxCoder Jul 25 '20 at 14:37
  • 1
    @horxCoder No the clip space coordinates are not in [-1, 1]. I've never said something like that. Neither the clip space coordinates nor the NDC are limited to a range. But in normalized device space the geometry inside the viewing volume is in range [-1, 1] (for all 3 components of the cartesian coordinate system). – Rabbid76 Jul 25 '20 at 14:39
  • In this equation: -w <= x, y, z <= w you say that this is the rule for clipping , meaning clipping should bring this , but it also implies that x, y and z should all be values equal to or between w , but w = -z(z coord in eye space) , then what is the guarantee that x, y cannot be greater that |w|? – horxCoder Jul 25 '20 at 14:41
  • @horxCoder We are talking about the coordinates after the perspective projection. The projection matrix also transforms the x and y component, dependent on the field of view. I've add a projection matrix to the answer. – Rabbid76 Jul 25 '20 at 14:43
  • The formula F_depth = 1/z - 1/near /(1/far - 1/near) is mapping the eye coordinates to [0,1]. There seems to be a transformation called depth range transformation involved. I've got two questions, how this F_depth formula was derived and whether this is equal to the viewport transformation? – horxCoder Jul 25 '20 at 18:07
  • um... certainly your answer has clarified one of the two points: when is this transformation done, but I am not quite clear, how the F_depth formula is transforming [-1,1] to [0,1], IOW, how we come to this formula. Sorry for the trouble, I will ask another question. E.g. look at this thread: https://community.khronos.org/t/when-and-how-does-opengl-calculate-f-depth-depth-value/106086/19 this has yet another formula for depth range calculation – horxCoder Jul 26 '20 at 05:05
  • I have asked the second part here: https://stackoverflow.com/questions/63096579/how-does-opengl-come-to-the-formula-f-depth-and-and-is-this-the-window-viewport . If you'd be kind enough to take a look at it and possibly answer it, it'd be greatly appreciated. :-) – horxCoder Jul 26 '20 at 05:58