Compute clip space .w from clips .xyz and (inv) projection matrix

I use a logarithmic depth algorithm, which causes someFunc (clipspace.z) to be written to the depth buffer, and separation of perspectives is not implied.

I do RTT / postprocessing, so later in the fragment shader I want to double-check eyepace.xyz, given ndc.xy (from the fragment coordinates) and clippace.z (from someFuncInv () for the value stored in the depth buffer).

Note that I don't have clippace.w, and my stored value is not clippace.z / clipspace.w (as it would be when using a fixed depth function) - so something like strings ...

float clip_z = ...; /* [-1 .. +1] */ vec2 ndc = vec2(FragCoord.xy / viewport * 2.0 - 1.0); vec4 clipspace = InvProjMatrix * vec4(ndc, clip_z, 1.0)); clipspace /= clipspace.w; 

... doesn't work here.

So, is there a way to calculate clippace.w outside of clippace.xyz, given the projection matrix or vice versa?

+6
source share
1 answer
 clipspace.xy = FragCoord.xy / viewport * 2.0 - 1.0; 

This is wrong in terms of nomenclature. "Place for clips" is the space in which the vertex shader is displayed (or any previous vertex processing step). Between the clip space and the window space is the normalized device coordinate space (NDC). An NDC location is a clip space divided by a clip space. W coordinate:

 vec3 ndcspace = clipspace.xyz / clipspace.w; 

So, the first step is to take the coordinates of the window space and get the coordinates of the NDC space. This is easy:

 vec3 ndcspace = vec3(FragCoord.xy / viewport * 2.0 - 1.0, depth); 

Now I'm going to assume that your depth value is the correct NDC space depth. I assume that you are extracting the value from the depth texture, and then used the near / far value depth range that it rendered to map it to the range [-1, 1]. If you have not done so, you must.

So now that we have ndcspace , how do we calculate clipspace ? Well, this is obvious:

 vec4 clipspace = vec4(ndcspace * clipspace.w, clipspace.w); 

The obvious and ... not useful, since we do not have clipspace.w . So how do we get it?

To get this, we need to look at how clipspace was calculated for the first time:

 vec4 clipspace = Proj * cameraspace; 

This means that clipspace.w computed by taking cameraspace and cameraspace it with its fourth line of Proj .

Well, that is not very helpful. This becomes more useful if we really look at the fourth line of Proj . Of course, you can use any projection matrix, and if you do not use a typical projection matrix, this calculation becomes more complicated (potentially impossible).

The fourth row of Proj , using a typical projection matrix, is actually this:

 [0, 0, -1, 0] 

This means clipspace.w really just -cameraspace.z . How does this help us?

This helps, keeping this in mind:

 ndcspace.z = clipspace.z / clipspace.w; ndcspace.z = clipspace.z / -cameraspace.z; 

Well, that’s good, but he just trades one unknown for another; we still have an equation with two unknowns ( clipspace.z and cameraspace.z ). However, we know something else: clipspace.z comes from dot-producting cameraspace with the third row of our projection matrix. The third row of the traditional design matrix looks like this:

 [0, 0, T1, T2] 

Where T1 and T2 are nonzero numbers. We will ignore what these numbers are at the moment. Therefore clipspace.z really just T1 * cameraspace.z + T2 * cameraspace.w . And if we know that cameraspace.w is 1.0 (as is usually the case), we can remove it:

 ndcspace.z = (T1 * cameraspace.z + T2) / -cameraspace.z; 

So we still have a problem. In fact, we do not. What for? Because in this euqation there is only one unknown. Remember: we already know ndcspace.z . Therefore, we can use ndcspace.z to calculate cameraspace.z :

 ndcspace.z = -T1 + (-T2 / cameraspace.z); ndcspace.z + T1 = -T2 / cameraspace.z; cameraspace.z = -T2 / (ndcspace.z + T1); 

T1 and T2 come directly from our projection matrix (the one with which the scene was originally made. And we already have ndcspace.z . Therefore, we can calculate cameraspace.z . And we know that:

 clispace.w = -cameraspace.z; 

Therefore, we can do this:

 vec4 clipspace = vec4(ndcspace * clipspace.w, clipspace.w); 

Obviously you will need a float for clipspace.w , not a literal code, but you will get my opinion. If you have clipspace to get camera space, you multiply by the reverse engineering matrix:

 vec4 cameraspace = InvProj * clipspace; 
+11
source

All Articles