# Direct3D Z order question

Aric Cyr Aric.Cyr at gmail.com
Mon Feb 13 04:17:27 CST 2006

```Stefan Dösinger <stefandoesinger <at> gmx.at> writes:

> I don't know much about GL drawing, but I noticed that GL clips primitive
> parts that are outside the Z range. So if vertices that were processed into a
> [0,5.3333] Z range are drawn into a [0,1.0] viewport leads to missing
> vertices. I guess I have to attend a few more courses at univertiy to really
> understand what exactly is going on.

There are two components to Z buffering, the first is the Z range and the second
is the near and far planes.  These work together to determine whether a vertex
is clipped (based on the near/far planes) and to what Z value it will obtain.

In OpenGL, first the vertices are clipped against the near/far planes (as
specified by glFrustum), then modified for perspective.  The near plane is
mapped to z=-1 and far plane is z=1.  All non-clipped vertices are now in [-1,1]
(called normalized depth coordinates).  Now window (i.e. viewport) depths are
calculated based on the Z depth range as specified by glDepthRange(r_near,
r_far).  Window depth coords range [0,1] though, so a linear transform is
applied to get from [-1,1] => [r_near,r_far].

> The relevant code is at dlls/wined3d/drawprim.c, line 186, vtx_transformed is
> true, useVS and vtx_lit are false.

Seems to me that the call to glOrtho should be replaced by a call to
glViewport(x,y,width,height) and glDepthRange(near,far).  Since your vertices
are already in viewport coordinates, according to the comment in the code, how
does something like the following work for you:

{
.....
/* reset projection matrix before modelview since
the glTranslate below should really be applied to
the modelview matrix */
glMatrixMode(GL_PROJECTION);
checkGLcall("glMatrixMode(GL_PROJECTION)");

glMatrixMode(GL_MODELVIEW);
checkGLcall("glMatrixMode(GL_MODELVIEW)");

/* Set up the viewport to be full viewport */
X      = This->stateBlock->viewport.X;
Y      = This->stateBlock->viewport.Y;
height = This->stateBlock->viewport.Height;
width  = This->stateBlock->viewport.Width;
minZ   = This->stateBlock->viewport.MinZ;
maxZ   = This->stateBlock->viewport.MaxZ;
glViewport(X, Y, width, height);
checkGLcall("glViewport");

/* depth ranges will be clamped to [0, 1] */
glDepthRange(minZ, maxZ);
checkGLcall("glDepthRange");

/* Window Coord 0 is the middle of the first pixel,
so translate by half a pixel (See comment above glTranslate
below)
*/
glTranslatef(0.5, 0.5, 0);
checkGLcall("glTranslatef(0.5, 0.5, 0)");
if (This->renderUpsideDown) {
glMultMatrixf(invymat);
checkGLcall("glMultMatrixf(invymat)");
}
.....
}

Regards,
Aric

```