Z divide fundemental question

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
damoos
Posts: 14
Joined: September 21st, 2019, 6:35 pm

Z divide fundemental question

Post by damoos » January 4th, 2020, 11:36 pm

I've asked this before, and usually get told to post my code. This is not a code problem, but a fundamental concept question. My code does exactly what I expect.

Lets say my view frustum is 10 units wide, 10 units high, and ten units deep.

Lets not do any FOV consideration, so near plane is 1;

Lets say I have a vertex at (-0.5, 0.5, 2.0) in world space.

After the projection matrix is applied, the NDC x,y portion coordinate of this vertex is (-0.2, 0.2). This makes perfect sense.

The original Z component was 2.0. It is stored in w. My code does all this as expected.

Here is what I don't understand. If I divide my new NDC x,y coordinates by the value stored in W, I'm dividing the scaled x,y coordinates by the un-scaled z value now stored in W. This can't be right, can it? The product on the screen seems to reflect exactly what I would expect from this. Extreme distortion cause by dividing by a too-large Z value.

Also, the projection matrix as shown by Chili, and all my texts does do NDC scaling on the original z component, but why isn't this the one I divide by?

I know I've posted this question in various ways quite a few times, but no one seems to understand what it is I'm asking! Posting code would be pointless! My code does as it I expect it to do. Its the fundamental concept I need!. Chili's example code for the 3D fundamentals series (where he teaches the projection transform) isn't helping me, because by that point in the series, he is using his shader system, and loading complex geometry. I haven't figured out how to follow a vertex through the pipeline yet. I'm sure one can, but I'd rather just discuss the fundamental concept here.

Thanks!

albinopapa
Posts: 3982
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Z divide fundemental question

Post by albinopapa » January 5th, 2020, 2:12 am

The coordinates of ( -.5, .5, 2.0 ) in world space, what are they in View space?

The projection matrix should scale the X, Y and Z and store the original Z in W after multiplying the vertex with the projection matrix.

If you aren't taking into account the view dimensions then you are probably going to get stretched objects in the X axis ( or squished objects in the Y axis ).

My last response in your previous post

Using:
view_width = 10
view_height = 10
view_near = 1
view_far = 10
We get a projection matrix of:

Code: Select all

[ ( 2 * 1 ) / 10,              0,                        0, 0 ]
[              0, ( 2 * 1 ) / 10,                        0, 0 ]
[              0,              0,          10 / ( 10 - 1 ), 1 ]
[              0,              0, -( 10 * 1 ) / ( 10 - 1 ), 0 ]
Simplified:

Code: Select all

[ .2,  0,       0, 0 ]
[  0, .2,       0, 0 ]
[  0,  0,  1.1111, 1 ]
[  0,  0, -1.1111, 0 ]
Multiplied with vertex:

Code: Select all

[ -.5 ] * [ .2,  0,       0, 0 ] = [ -.1,  0,       0, 0 ]
[  .5 ] * [  0, .2,       0, 0 ] = [   0, .1,       0, 0 ]
[ 2.0 ] * [  0,  0,  1.1111, 1 ] = [   0,  0,  2.2222, 2 ]
[ 1.0 ] * [  0,  0, -1.1111, 0 ] = [   0,  0, -1.1111, 0 ]
----------------------------------------------------------
                                   [ -.1, .1,  1.1111, 2 ]
Now, W divide:

Code: Select all

-.1 / 2 = -.05
 .1 / 2 =  .05
1.1111 / 2 = 0.55555
2 / 2 = 1
The resulting vector after projection and W divide ( -.05, .05, .5556, 1 ).

Now, convert that back to 2D screen coordinates: ( w = 10, h = 10 )

Code: Select all

x = ( -.05 / 2 ) * 10 = ( -.025 * 10 ) = -.25
y = (  .05 / 2 ) * 10 = (  .025 * 10 ) =  .25
You end up with ( -.25, .25 ) which is half which would have been the same as dividing your original ( -.5, .5, 2 ) by 2.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 3982
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Z divide fundemental question

Post by albinopapa » January 5th, 2020, 2:47 am

You can use the debugger to step through lines of code. Just set a break point on a line, then press F11 to step through one line of code at a time.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

damoos
Posts: 14
Joined: September 21st, 2019, 6:35 pm

Re: Z divide fundemental question

Post by damoos » January 5th, 2020, 2:50 am

First off, sorry I didn't notice your lengthy response to the prior post. Slipped through the cracks in my haphazard world! Thanks for going to the effort! Bad form for me to not have noticed. Apologies.

Also, I actually do consider aspect ration in my code. Just didn't here for simplicity.

Ok, I was with you up to and including the W divide.

Your "back to 2d screen coordinates" step is new to me. I thought after w divide, one then converted to actual physical screen coordinates. Am I missing something?

Thanks for the help, this is exactly the conversation I was looking for.

damoos
Posts: 14
Joined: September 21st, 2019, 6:35 pm

Re: Z divide fundemental question

Post by damoos » January 5th, 2020, 2:53 am

Oh, I do know how to use the debugger. Its just finding the right places to watch is difficult in the version of the demo that has this portion added. Its obscured (at least for me) by the shader system, and the fact that the geometry is loaded externally, rather than a simple in code defined cube for example. I admit I should probably dig a bit deeper on this point.

albinopapa
Posts: 3982
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Z divide fundemental question

Post by albinopapa » January 5th, 2020, 7:44 am

damoos wrote:
January 5th, 2020, 2:50 am
First off, sorry I didn't notice your lengthy response to the prior post. Slipped through the cracks in my haphazard world! Thanks for going to the effort! Bad form for me to not have noticed. Apologies.

Also, I actually do consider aspect ration in my code. Just didn't here for simplicity.

Ok, I was with you up to and including the W divide.

Your "back to 2d screen coordinates" step is new to me. I thought after w divide, one then converted to actual physical screen coordinates. Am I missing something?

Thanks for the help, this is exactly the conversation I was looking for.
In the projection matrix, you multiply by 2 then divide by screen width. So the reverse is divide by 2 then multiply by screen width...same with height.

I understood that the 10x10x10 view was for simplicity and it actually helped explain things and the math was super easy because of it. I knew there was something amiss in your understanding of the projection matrix, just glad we got to the right part. I thought you might have gotten a bit frustrated and either didn't read the previous thread or just didn't understand what I posted so no worries, though thanks for the apologies and acknowledgement, I thought about being a bit snarky in my reply and now I'm glad I wasn't :).
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 3982
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Z divide fundemental question

Post by albinopapa » January 5th, 2020, 7:51 am

If it's the 3D fundamentals framework, the shaders are all C++ code that you should be able to put a break point on the first line of the Pipeline::Draw function and step through it from there. First the vertices are passed through the vertex shader, as you step into the shader you should be able to see what the values are before and after. Then it goes through a backwards facing culling phase, anything that makes it through that gets passed to the frustum clipping and culling function. Anything that makes it through that phase is passed to a function where the W divide happens, the chili named "PubeScreenTransformer". The transformer halves the values then multiplies by the screen dimensions. It also inverts the Z so that the interpolation of the Z values is linear between vertices.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

damoos
Posts: 14
Joined: September 21st, 2019, 6:35 pm

Re: Z divide fundemental question

Post by damoos » January 6th, 2020, 2:28 am

ok, I'm still a bit confused.

Just to be clear, my 10x10 is the frustum size, not the physical screen size.

Just to insure we are are on the same page here, we still need to convert to the (in my case ) 640 by 480 physical screen.

I'm actually still confused here. Let me ignore actual coordinates, and just describe the steps as I (probably incorrectly) understand them.

1: My geometry exists in world-space. We'll call 1 a unit. Lets say my world is 100x100x100 units.

2: My view frustum is a 3d window into a segment of world-space. In my example, it is a 10x10x10 chunk.

3: My physical screen is 640x480 pixels

4: The projection matrix takes my geometry in world-space, and scales it such that objects that were in the 10x10x10 frustum are now in the range of -1 to 1 in all axis. At this point, x an y are scaled completely, the original z is stored in w, and the z in the scaled vertex is partially scaled pending the w divide.

5. Next, I divide everything by w (which contains the original un-scaled Z). Dividing Z by W completes the scaling of Z. It perspective scales x and y. This is where my confusion lies. We just finished scaling Z (with the w divide), but have used the un-scaled version in W to perspective divide x and y.

6: Here is where I think there is a step I'm missing?

7:Now we take the -1 to1 NDC scaled vertices, and convert them to my 640x480 physical pixel locations.


Obviously, I'm not including any culling here for simplicity of discussion.

I think you are trying to explain the mysterious step 6 to me. Am I properly describing the other steps?

albinopapa
Posts: 3982
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Z divide fundemental question

Post by albinopapa » January 6th, 2020, 5:03 am

At this point, x an y are scaled completely, the original z is stored in w, and the z in the scaled vertex is partially scaled pending the w divide.
Okay, after you multiply the vertex position by the projection matrix, the X, Y and Z coordinates are in a new coordinate system relative to how your view frustum is setup. So as you said, if they are in view then between -1 to 1 in X and Y and 0 to 1 in the Z. This has nothing really to do with the perspective yet. The W divide puts it in perspective by making distant things smaller. The projection matrix just changes the coordinate system form 640x480x10 to 2x2x1 ( -1 to 1, -1 to 1, 0 to 1 ). There's probably a couple reasons for this. One, floating point math is more accurate using small numbers. Two, a normalized range is ambiguous to screen resolution changes. So the projection matrix just puts everything in this ambiguous coordinate system. Dividing by depth should be the same regardless of what the resolution is, if Z is 2, divide by 2 whether it's NDC or physical pixels.

This is what creates the illusion of depth. If you scaled the depth say 2 / 10 ( .2 ) that would be the same as multiplying by 5 and at a depth of 10 it would be multiplying by 1 so it would be original size at the far end of the frustum. So you need to divide by an unscaled Z value, the W.

After the W divide, the scaled Z is ONLY used to determine if it is closer than the pixel it might be replacing.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply