z-buffer work around


The so called artifacts you claimed I saw are as I said the reverse facing surfaces blended into the front facing surfaces.
I made sure of this. By reducing the scale of the object then producing it normal then turned on blending and it was identical.

We are talking about “back” faces, not all hidden faces, ok ?
Most probably your are doing something wrong.

Screenshot and code please ?

Why would precise z values effect backface culling?

Or, to be more descriptive, why would a 2D clockwise/counterclockwise algorithm ever pay attention to z values?

My theory is that you did not enable backface culling and your extreme z buffer setting revealed the artifacts.

It doesn’t help the final storage, but it helps the computations leading up to the final Z value. It helped a lot for Z-fighting in the distance in our engine, even though we use fixed point Z. I was actually a bit surprised myself how big impact it had, even with a fixed point buffer.

No it’s not. Period.
You’re either misunderstanding something, or you have a bug.

The depth is irrelevant to backface culling. X and Y is sufficient. Check the OpenGL spec, section 2.14.1, equation 2.6.

If you got perspective projection, those screen-space X,Y coordinates depends on the depth of the vertex, no? Still, I would be very surprised if the Z-buffer precision affected the coordinate transformations in such a way (any way really).

Why the issue happens 100% I am not sure. But I do know if I bring the object at a much smaller size very close to camera the z-buffer does work. Only when I expand the object either by me or using opengl scale and move it to a comparative view size and distance then the z-buffer and such fail.

When up close if you press the first surface you can not see the rear surfaces. But once expanded it does not hold true.

I am not sure so much if it is a pure clock wise counter clock wise check they do. My guess would be do to the limited bits assigned at that range the system is unable to determine which faces are closer. There for it samples from both. But it could be just crap code by both companies creating an identical problem, doesn’t seem likely unless one copied the others code exactly. In other words I doubt that, I think it has to do with the precision issue.

Here is the test project only where I was trouble shooting the problem. Yes, I am 100% sure that the back face culling was enabled. So are a large number of programmers on other sites like gamedev.net where I first brought the issue up.

The reason I brought it here wasn’t really to discuss if the issue exists it is to find out what workarounds people have came up with for it.

So to make the point I been through the code and so have a lot better programmers than myself. The Z-buffer problem is well a well known issue. I just want to see what workarounds people have came up with.

Things like oct-trees sphere trees and so on only work to a limited extent unless you are going to does so to a polygon level.

By the way the test code in the project above is just that nothing more. It is seriously a mess and has been up-down modified to test most aspects by commenting stuff in and out.
It is a VC++ 6.0 project.

Backface culling doesn’t try to determin which faces are closer/further away. It tries to determin whether or not any given triangle is facing towards the camera, or away from the camera.

Originally, I assumed that this was determined by testing a triangle’s normal’s z component for positive or negagtive Z. (assuming the normal has been translated into screen-space coordinates)

I was corrected and told that it uses a winding test against the x and y components. If the triangle winds one way, it is facing the camera. Otherwise it is facing away from the camera.

Was there a link to your code?
I didn’t see anything.

Also, what is the answer to the question:
Are you making a space-based game? (stars, planets, spaceships, etc…)

If so, is your problem only associated with rendering terrain while near a planet? Or a problem of rendering space-born objects from space? Or a combination?

There was a link not sure why it didn’t show it but showed the other one. weird.


No not currently making a game. I was thinking of building just a graphics engine but wanted to know what the hardware limits were these days. From talking to others it looks like the z-buffer issue has been kind of sat on for a long time. A lot of game companies are trying to rewrite engines at present time to give better depth and implement larger scenes with more detail. Most are finding they are having to take advantage of the multiple CPU technology to handle this because the one place the GPU hasn’t advanced in 10 years is the z-buffer.

I think the issue is a lot of the time referred to as z fighting.
You can force it to happen in games you can make your own levels such as unreal and so on. They have came up with a number of solutions most of which means part of the scene does not get drawn. Fog, multidrawing then clearing the z-buffer between hand.

All of which have limits.

If you want to test what I am saying try this.
set your near to .1 and far to 1,000,000,000
create a sphere with multi colored faces about 67,000,000 radius put it out at 300,000,000
enable back face culling
What you will see is a sphere that looks like blending is turned on and you can see the surfaces on the back side.

The sad part is I can do this entirely on software and create my own z-buffer and rasterizer which is what I did over 10 years back and it will display perfectly.

Anyway it boils down to if you want a massive scene you have to do a few things make sure no objects are behind one another,
if you have a partially obstructed object you will need to split or subdivided the surfaces to get better visibility and only display the ones not obstructed. You will also have to manually back face cull.

Which means all that work that was done for years to move work from the cpu to the gpu just went up in smoke and amounts to a hill of beans.

One place this fix would come in real handy is with medical imaging. They receive near real time data and need to go from far out to extremely close up. It would greatly improve images and cut cost of the equipment.

Not to mention game environments could be made far larger than we currently are making them and make the ease of creating them far easier and less cpu intensive.

Just my thoughts on it

Yes, it depends on W, but not on Z or Z/W that’s used in the depth test.

The problem is that you’re confusing the backface culling with the depth test. The backface culling is working perfectly from what I can tell running your app. The faces that bleed through are all front-faces. You have z-fighting though, but that’s hardly a surprise at these settings.

Why do you say that? The Z-buffer has advanced at least as much as the rest of the pipeline. 10 years ago a lot of hardware didn’t even have one. The ones that did had a 16bit one. Since then we’ve added 24bit, 32bit floating point buffer, depth textures, a whole bunch of optimizations (HiZ, EarlyZ, Fast Z clear, Z-Compression), depth bounds test, depth clamp etc.

Sure, and it’ll render at 1/1000 of the performance of a video card. Yes, software is more flexible. It has always been and will always be. If we made GPUs as flexible as CPUs then they would also run at the speed of the CPUs, which would make it pointless. GPUs are specialized to handled normal rendering tasks. Your rendering case is extreme, so no one has spent any effort trying to accelerate it. It’s not normal to have a planet/pea ratio. If you need doubles then there’s only RV6x0 based cards that supports that yet, and that’s not even exposed in any API now other than for GPGPU, and you’d still have to implement your own depth buffer emulation. Keep in mind that it was only a couple of generations since we even got floats.

First off, I am not getting depth testing or z-culling confused with back face culling.
Z-culling or depth testing simply puts the approximate depth of a pixel in a buffer or assigns it associated value based on depth as in opengl it either 0 to 1 or -1 to 1 depending on what articles you read. But the fact is they use perspective to assign bit values. so what is closer has greater depth.

This however is similar to w-buffer which is a pure float that is independent for each pixel and can actually give a better image in many cases.

Back face culling or winding tests work in one of two ways by either comparing 2 vectors one from the view point direction out ward to the surface normal. That is not used on most hardware in fact I can not think of a hardware implementation off the top of my head not saying it doesn’t exist.

Then there is screen winding. Faster than the vector test method but has limitation that come to lighting and shading.

I hope that establishes I know what the difference is.

Now my issue since you seem to miss the point over and over again I will step through it.
Use my test project if you must.

Take the same object make it small and view it close up you will see back face culling is working perfectly when you break the frontal surfaces you will not see the rear ones nor do you get artifacts or more precise see the rear surface.

That should establish the back face culling works fine.

Now enlarge the object and watch the surface start to show through and z-fighting begin.

Now that we know the back face culling is implemented correctly and yet we are getting z fighting.

Explain how that is happening.

Those other surfaces should not exist if the back face culling worked.

How is it then that the surfaces that should be back faced culled are still showing up if they are not tied into the screen depth algorithm?

I know the settings are at fault for it z-near and z-far. They affect how far the z-buffer is spread out. However even if you change to 32 bit mode in my setup.txt file it isn’t enough. it would require large number of bits or more to come close to that scale of variance. Which is funny a 32bit W-buffer would still out perform it. because most the detail would get wasted up close on the z-buffer. A 64bit w-buffer would slaughter it.

One of the better ideas I heard to over come the limitation was a variable z-far and z-near and clear the z-buffer between them. It would mean each object or parts of objects would require being ordered from far to near then taking those objects and displaying them with different z-far and z-near values which would mean you would also need to scale the to bottom left right as well to get the correct perspective and screen position.

Then there is the idea of object culling, frustum culling, then back face culling surfaces and making sure partially covered surfaces are split and then only the visible surface displayed.

Anyway no matter what method is used to over come this problem it means dumping far more work back on the CPU that really could be better handle on the CPU with a different implementation.

Then there is a second down fall each requires even more calls to display an object.

Unfortunately you are the one who is missing the point.

Back face culling removes faces at which you look from the incorrect (back) side. It does not care if the face is hidden by something else. As long as you see the face from the correct (front) side, it will pass the back face culling. The correct ordering of faces is job of the depth testing.

Because your planet is not convex, there are situations when you see two faces from the front side while they overlap on the screen (those are the faces you see as the artifacts). Both faces will pass the back face culling (because you see them from the front side). If the depth test works, only the closest from them will be visible. If it fails (because of the extreme depth range and limited buffer precision), the one which is drawn as last will be visible resulting in artifact you see.

I will suggest simple experiment. Add a key to your program which will toggle on and off the depth test. Now use the small planet which looks correctly and disable the depth test. You will see similar kind of artifacts you are seeing on the big one. Now add a key which will toggle the back face culling. As before use the small planet and toggle it. You will see that the artifact does not appear.

Anyway no matter what method is used to over come this problem it means dumping far more work back on the CPU that really could be better handle on the CPU with a different implementation.

Then there is a second down fall each requires even more calls to display an object.

GeorgeRH, you don’t know what you are talking about, at all.
You can store an insane amount of geometry and texture and shaders on the GPU and draw even a very complex scene in just a few draw calls, with almost zero use of CPU, only GPU side will be used. Then simply repeat those few calls multiple times, each with specific znear/zfar ranges. Ie [1-1000[ then [1000 1000 000[ then [1000000000-1000000000000[ … Hardly taxing on the CPU side, and the GPU will still be mostly asleep to draw your current scene :slight_smile:

Please don’t behave as someone who know about it (you don’t, everybody agrees on that) and stop complaining (as you have no reason to), that way you can still get good advice from experienced people.

Modern hardware is good, but it isn’t perfect.

Would people like a higher resolution z-buffer? Sure!

Would we like to use 4-byte floats for color components rather than 8 bit unsigned integers that pretend to be floats? Sure!

Would we like more programming language features in shaders? Sure!

Would we like a blend shader? Sure! (this is what I want)


Many of these things are already possible, with the more recent GPUs. More of these things will become available over time.

The problem many here have with your post is:

You make it sound like the graphics industry went off in the wrong direction for the past decade. Somehow, forgetting to consult you first. (In spite of the fact that you haven’t been a part of the graphics industry for the past decade)

You also imply that there is some large, faceless mob of angry programmers who meet on a regular basis just to bemoan the lack of floating point zbuffers.

On this board, I have seen many people seek help with various problems. I haven’t heard anyone complain about zbuffer precision. That doesn’t mean that no one has had that complaint, but just don’t recall seeing it lately. I have no doubt that it has been an issue for a few individuals. However, it is not some industry-wide holocaust issue that we are all struggling with every day.

Everyone has their own personal “wish list”.
A set of features that would suddenly make their projects much more strait-forward to code.

Life goes on. You either scale back your goals. Or write specific work-arounds for problems. Or reduce your target platform to just the high-end cards that support feature X, which solves your problem.

People on this board, who have many years of experience, have been trying to suggest work-arounds for your problem.

Listen to them.

The most common solution that has been suggested is:

Break your rendering pass into seperate passes based on depth levels. For each group, set the z_near and z_far to envelope that group’s depth extents. These depth-groups should be sorted far-to-near.

How should you do this?
We can’t tell you exactly.
It depends on what your data is like.

If it is a bunch of planets, moons and stars, you could practically render each heavenly body in it’s own seperate z-range pass.

If it has lots of objects that partially occlude eachother and occupy the same space, (like small space craft flying near larger space craft) then you would need to group them into clusters of objects that have similar depth ranges and render them with a z-range that encompasses them.

If it involves rendering mountains and other distant terrain along with details right under your feet, then there are other methods you could use.

Tell us some specifics, without the attitude, and people will make more specific suggestions to solve your problem.

These people love this stuff.
It is often their hobby as well as their job.

Komat and all: You are right on that issue, I missed your point. The surfaces showing through are just the ones that happen to face forward at the time because the elevation change.
Thanks, for restating it again. Guess I just needed it drilled in one more time. Sorry on that everyone.

Your right also on the bitching and complaining sorry again.

I do know as you said the geometry and much of the data can be left on the gpu side or video buffer.

Maybe, what I should be asking is a better question.
The shader technology today. Is it capable or being used to reorder the calling of the geometry.

In other words calling the objects from far to near or more precise the vertex data and the changing the z-near and z-far and so on? Then of course the z-buffer would be need to be cleared in between each new progressive step.

The project isn’t aimed at one small area. Planets and so on is really a test data set. The reason for using it is it gives a good example of scale and change in perspective. Or something like the human brain and you wanted to go from seeing the entire thing to seeing a single cell.

I know ATI had on the rage model in 1999 16,24,32 bit z-buffers. Then I am not sure on Nvidia and 3dFX.

Guess I need to do some research into what can actually be done with newer shader technology.

To use the approach ZBuffeR and others suggested, you don’t have to sort all the objects. You just have to determine if the objects fit into a particular depth interval. This is a O(n) operation and can be performed on the CPU really fast.

Even not needed. Object outside the znear/zfar will be clipped away automatically by the GPU.
So you can choose your tradeoff between CPU usage, GPU usage, and complexity of code, with more or less precise CPU culling.

Hi guys,

Because of this thread I started experimenting with projection matrices and the impact of the 3rd row on the z-buffer accuracy. Just for fun I tried to replace the 3rd row of the projection matrix from glFrustum with the 3rd row of the projection matrix from a glOrtho call with the same near/far values.

Small note: It does appear to experience some weird behavior when resizing the window. Don’t know why…

To my surprise, this seems to work. The problem is, mathematically this doesn’t add up. In ortho mode near/far maps to [-1,1] (clip space) and the w coordinate remains 1 after projection so there’s (theoretically anyway) no division to get to normalized device coordinates. However, in the matrix I set up near/far still maps to [-1,1] but the w-coordinate is equal to -Z. So there should be a division by w before the depth values get interpolated, no? If so, then why are the depth values I read out still in the range [0,1].

I’m only asking this question to get a better understanding of what calculations are actually being done by the hardware and at what times. I thought I figured everything out like perspective correct interpolation using barycentric coordinates while depth values are linearly interpolated in screen space, etc. but after encountering this issue it looks like I have to think twice :slight_smile:

Just my guess on this.
If I placed all the objects that were in side the view frustum and just started from far to near I could just call the entire buffer as Z-Buffer the stuff out side it would be automatically culled by hardware. Then as I step closer I correct the frustum and clear the Z-buffer.

To be honest I am having a bit of trouble implementing this. I want to do it manually then I’ll move it over to a VBO and such to do what I can. When I do get it to display it still shows the same problems. So obviously I am doing it wrong.

When changing the frustum I need to first step back to projection view to start with?


//back to model view to do my translations

//translations here

//clear z-buffer here

//then redraw here