PDA

View Full Version : ZBuffer and matrix changes



chronozphere
24-02-2007, 01:24 PM
Hi PGD'ers. :)

I have discovered something weird.

The Z buffers isn't working properly when you change your projection matrix. I had this problem with my engine so i decided to test it using one of clooties tut's. :)
My engine supports different view/projection matrices to be used in one scene. So it is possible to render with perspective/orthogonal/screen coordinates etc.
But this requires changing the projection matrix, and that delivers a wierd result.
I've used this code to test. (its from the Mesh tutorial in clooties SDK, just replace the render code with this code).


procedure Render;
var
i: DWORD;
matWorld,matProj,matView: TD3DXmatrix;
begin
// Clear the backbuffer and the zbuffer
g_pd3dDevice.Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,255), 1.0, 0);

// Begin the scene
g_pd3dDevice.BeginScene;

//setup matrices
D3DXMatrixRotationY(matWorld, timeGetTime/1000.0);
g_pd3dDevice.SetTransform(D3DTS_WORLD, matWorld);

D3DXMatrixLookAtLH(matView, D3DXVector3(0.0, 0.0,-5.0),
D3DXVector3(0.0, 0.0, 0.0),
D3DXVector3(0.0, 1.0, 0.0));
g_pd3dDevice.SetTransform(D3DTS_VIEW, matView);

D3DXMatrixPerspectiveFovLH(matProj, D3DX_PI/4, 1.0, 1.0, 100.0);
g_pd3dDevice.SetTransform(D3DTS_PROJECTION, matProj);

//render first tiger
for i:= 0 to g_dwNumMaterials - 1 do
begin
g_pd3dDevice.SetMaterial(g_pMeshMaterials[i]);
g_pd3dDevice.SetTexture(0, g_pMeshTextures[i]);

g_pMesh.DrawSubset(i);
end;

//translate second tiger
D3DXMatrixTranslation(matWorld, 1,0,0);
g_pd3dDevice.SetTransform(D3DTS_WORLD, matWorld);

//set new projection matrix
D3DXMatrixOrthoLH(matProj, 5.0, 5.0, 1.0, 100.0);
g_pd3dDevice.SetTransform(D3DTS_PROJECTION, matProj);

//render second tiger
for i:= 0 to g_dwNumMaterials - 1 do
begin
g_pd3dDevice.SetMaterial(g_pMeshMaterials[i]);
g_pd3dDevice.SetTexture(0, g_pMeshTextures[i]);

g_pMesh.DrawSubset(i);
end;

g_pd3dDevice.EndScene;

g_pd3dDevice.Present(nil, nil, 0, nil);
end;


The weird thing is that the second tiger is ALWAYS drawn over the first tiger. No matter what value i use for the Z translation of the second tiger. There is no way to make the meshes intersect, it's just like rendering 2d images of a tiger.
The ZBuffer was enabled during these tests.

What is the cause of this?? does D3D reset the zbuffer every time you change the projection matrix??

thanks in advance. ;)

JSoftware
24-02-2007, 01:30 PM
Edit: Damn I can't read today.. Nothing here...

Clootie
25-02-2007, 12:03 PM
Hmmm.... When you are change projection matrix you also change mapping of Z axis from your "world/view" space to post-transform space. While generally you could "compose" correctly between difference matrices - when switching from Ortho to Projection transformation is really impossible to get 100% correct composition.

chronozphere
25-02-2007, 01:11 PM
Okay i did some more testing and the problem also occured when i mulitplied world/view/projection matrices and passed them to D3D as world matrix. So D3D doesn't change the ZBuffer, it's a pure mathematical problem.

Not that i find perspective and ortho projections in one scene a usefull feature, i was curious whether it would work correctly, and it didn't work.

But i dont understand why it doesn't work. :?
What's exactly the difference between a perspective and an orthogonal projection. Are the following things true??

An orthogonal field of view can be visualized as a box.
The positive Z axis is pointing away from the viewer's eye.
The only difference between a perspective and an ortho projection is that in perspective projection, the front face of the box is scaled so the box becomes a frustum. This has no influence on the Z axis.
So i dont know why you say this:


Hmmm.... When you are change projection matrix you also change mapping of Z axis from your "world/view" space to post-transform space.


When you set the far/near planes to fixed values for both perspective and orthogonal, i dont see the problem. :?
Why is the Z Mapping different??

Can someone clarify this?? (Maybe a link would help) ;)

JSoftware
25-02-2007, 02:31 PM
My guess based on my own logic tells me that the zbuffering in a perspective projection would differ from orthographic projection in a way like this:
http://img219.imageshack.us/img219/3377/zbufferae9.jpg (http://imageshack.us)

chronozphere
25-02-2007, 04:01 PM
uh :eh: I dont think that's possible. You can't bend a space with a matrix. can you?? It requires some funcky math to do that.
If the space is bended, the far and near planes should also be bended and that is, mathematicly, a lot of work.

My logic tells me, that your drawing is correct, except for that bended line. I think that must be a straight line.
So i still dont understand why z is mapped differently. :?

Clootie
25-02-2007, 07:59 PM
chronozphere
Have you studied D3DXMatrixOrthoLH() (http://msdn2.microsoft.com/en-us/library/bb205346.aspx) and D3DXMatrixPerspectiveFovLH() (http://msdn2.microsoft.com/en-us/library/bb205350.aspx) documentation? Look how Z coordinates being calculated. And even worse - W coordinate gets different values too.

JSoftware
While intersection of Z planes with projection pyramid will be lines as chronozphere pointed - you are still kind of right too. Texture LOD calculation at lines parallel to front/back plane will "behave" something like you've drawn (as one/both texture coordinate line will change directtion per dx or dy -- i.e. at least one of the du/dx; du/dy; dt/dx; dt/dy will change).

chronozphere
26-02-2007, 11:32 AM
ah yes... it's transformed differently. ;)

But that raises another question:

I've read somewere that all visible geometry must be transformed to the canonical view (an AABB with dimentions X [-1,1] Y[-1,1], Z[0,1]).
The orthogonal matrix contains this (for Z coordinate):

1/(zf-zn)

and z translation:

-zn/(zf-zn)

That makes perfectly sense. It scales all geometry, so it fits in the canonical view, and translates it to remove everything in front of the near plane.

But i dont understand the perspective Z calculation.

zf/(zf-zn)

When zn is very low (almost equal to zero) this formula returns a value that's allmost one. So when i:

>>Set zf to 2000 and zn to 10.. the formula returns: 2000/1990
and the translation is ~10

When i use the matrix to transform a vertex with Z = 1000
the resulting Z value is ~995 wich is way outside the canonical view. So i guess the vertex isn't visible. :?

This explains why geometry rendered with ortho projection is rendered in front of the perspective stuff. Z values for ortho projection always lie in the range [0,1] and those for perspective projection in the range [0,zf-zn]. :)

Can someone clarify this?? :?

Clootie
26-02-2007, 08:24 PM
Actually clipping volume is:
-wc<= xc<= wc
-wc<= yc<= wc
0 <= zc<= wc

So after transformed coordinates divided by W - you get expected [-1; 1] & [0; 1] range (for Direct3D). OpenGL uses [-1; 1] for all coordinates.

chronozphere
27-02-2007, 08:36 AM
Thank you very much :D Things are clear now.

So i could compose my own matrix wich doesn't use W, just the same method as the orthogonal matrix. This would solve the problem.

But, is W usefull?? what would happen if i don't use it in the matrix. :?

Clootie
27-02-2007, 09:02 AM
You will not get perspective correction of vertex attributes (colors, texture coordinates)... - not a good idea 8)