JoeyDewd 1216 Report post Posted July 20, 2014 I'm currently trying to figure with what equation the non-linear depth value of the fragment's gl_FragCoord.z value is calculated. I know how to transform the fragment's depth values back to their linear equivalent, but I couldn't find any good resource on the reverse operation. Currently my shader uses the following function to transform the gl_FragCoord's z-component to its linear variant, but what equation is used for transforming from the linear to the non-linear value? So from view-space z value --> screen-space z value. Shader code: float LinearizeDepth(float depth) { float near= 0.1; // camera z near float far = 100.0; // camera z far float z = depth * 2.0 - 1.0; // Back to NDC return (2.0 * near) / (far + near - z * (far - near)); } void main() { float depth = LinearizeDepth(gl_FragCoord.z); // <-- Some equation that transforms it back to the original gl_FragCoord.z value? color = vec4(vec3(depth), 1.0f); } Any insight would be appreciated. 0 Share this post Link to post Share on other sites
Waterlimon 4398 Report post Posted July 20, 2014 You should be able to just do the inverse operations in the exact reverse order to do that (+ becomes -, / becomes * and apply operations in reverse order) 3 Share this post Link to post Share on other sites
JoeyDewd 1216 Report post Posted July 20, 2014 Hey Waterlimon, That makes sense though, although I never really polished any of my algebraic skills (should probably start doing that soon). I've switched the operators, and applied the operations in reverse order. I then return the (supposed to be) original value of the depth buffer, but the visual output is an all white terrain where the depth value does not seem to get any less than 1.0 (used to do that) so it's probably not correct: float near= 0.1; // camera z near float far = 100.0; // camera z far float z = depth * 2.0 - 1.0; // Back to NDC float dep = (2.0 * near) / (far + near - z * (far - near)); float v = (far + near / (far - near + dep)) * (2.0 / near); return (v + 1.0) / 2; // Back to [0,1] range. Is there any error I made with the inversion of the function? 0 Share this post Link to post Share on other sites
MJP 19754 Report post Posted July 20, 2014 You can also just apply your original projection matrix and then divide the result by w 1 Share this post Link to post Share on other sites
JoeyDewd 1216 Report post Posted July 21, 2014 Retrieving the result via the original projection matrix is an option yes, but for educational purposes I was interested in the equation. I managed to retrieve the inverse equation for the linear -> non-linear case: z_non_linear = -((near + far) * z_linear - (2 * near)) / ((near - far) * z_linear) Testing the equation on a single test value should eventually return the same value which it does: z = 0.9, near = 0.1, far = 100 z_linear = 0.2 / (100.1 - 0.9 * 99.9) = 0.01962708537782143 // from non-linear -> linear z_non_linear = -(100.1 * 0.01962708537782143 - 0.2) / (-99.9 * 0.01962708537782143) = 0.9 // from linear -> non-linear So the equation works out :) Although I'm not sure if there are any more simplifications left to make the function a bit more aesthetically pleasing? Thanks for the help 0 Share this post Link to post Share on other sites
Jason Z 6434 Report post Posted July 22, 2014 Retrieving the result via the original projection matrix is an option yes, but for educational purposes I was interested in the equation.This is obtained by using the original projection matrix, and just taking the z component. As long as you know how your projection matrix is constructed, then you would have the symbolic equivalent of your equation quickly and easily! 1 Share this post Link to post Share on other sites
JoeyDewd 1216 Report post Posted July 22, 2014 Yeah, I'll be sure to invest some time into properly understanding the projection matrix's inner workings. That'll save me questioning this kind of stuff 0 Share this post Link to post Share on other sites
JohnnyCode 1046 Report post Posted July 23, 2014 Try to multiply view matrix with projection matrix by hand and see the 4th row of the result- the w component construting row. You will notice it just contains the third view matrix row in the very resulted matrix 4th row: view matrix projection matrix [a,b,c,p1 ] [a,b,c,p2 ] [vx,vy,vz,vp] BLA [0,0,0,1 ] [0,0,1,0] if we consider column matricies and multiplication order , then we multiply view column with projection row. first component in 4th row of result: [a,a,vx,0]*[0,0,1,0]=vx second component in 4th row of result: [b,b,vy,0]*[0,0,1,0]=vy third component in 4th row of result: [c,c,vz,0]*[0,0,1,0]=vz fourth component in 4th row of result: [p1,p2,vp,1]*[0,0,1,0]=vp thus, bottom 4th row of view*projection matrix is actualy the third row of the view matrix. If a vector gets tranformed by this matrix, it actualy remembers its previous pre-projection transformations z component in its final w component. That is the linear z- the w komponent. And the final vector that gets rasterized (depth tested and so on )is (x/w,y/w,z/w,w) - this should be glFragCoord value, but of course interpolated across triangle after vertex function. 0 Share this post Link to post Share on other sites