I’m rendering some things in different projection modes. One thing whith a perspective projection, and another with an ortho. My question is this:

I want objects rendered in both setups to have depth values that “make sense” together. I’ve set both with nearplanes at 1 and farplanes at 300. Now shouldn’t that mean that a flat quad with a z of, say, -80, should yield the same depth buffer values with either projection mode?

The problem is I have a screen-oriented quad I’m drawing in ortho mode, but it seems that it is always considered to be nearer the nearplane than another object that should actually be in front of it. Is there a reason why a screen-oriented quad drawn at -80 should have depth values such that it is drawn in front of an object drawn at -25?

The depth buffer values in perspective projection does not have a linear distribution between the near and far clip plane, which is the case for orthographic projection. The distribution of the precision over the view volume depends on the ratio of the near and far clip plane values; larger ratio, more precision closer to the near clip plane.

That is why you have precision problems in the depth buffer when you abuse the near clip plane. Even a tiny absolute change in the near clip plane can cause the ratio to increase a lot and kill the depth buffer.

I see. Well, I finally was able to get my quad to draw where it seemed to be at approximately -80 in relation to my other object that was being perspective projected. I had to set the Z of the ortho quad to -296 (in a range of 1-300) to match the approximate depth of -80 (in a perspective range of 1-300).

Is there a way to get these values without the guess work?

You can get the depth buffer values by multiplying a point with arbitrary x and y, and with the desired z, by the projection matrix (*). Multiply by the inverse of the projection matrix to go the other way. This way you can convert between world Z and the corresponding depth buffer value.

The orthographic matrix is quite simple, you just do a linear interpolation between the near and far clip plane.

The perspective projection is a bit tricky, so lucky for you I have done them already. Basically, I got them by transforming a point by the projection matrix, do the perspective division, and compress the range to [0, 1]. This is what I got.

%in: wZ - world Z
%in: near/far - near/far clip plane
%out: fbZ - value written to depth buffer

a = -(far - near) / (2 * far * near);
b = (far + near) / (2 * far * near);

Note: In the formula, wZ is actually the distance between the origin and the point. A point in the middle of your view volume (range [1, 300]) will have a wZ of 150, not -150 as one would expect since the negative Z-axis is poiting into the screen. Dunno why I made it that way

Using this formula, you can project a world Z to depth buffer Z, and then you use linear interpolation to get the corresponding world Z with orthographic projection.

(*) Actually, the projection matrix gives you a value in the range [-1, 1], so you also need to translate this to [0, 1].