🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Clear depth in the middle of frame?

Started by
9 comments, last by Geri 1 year, 8 months ago

I'm working on a full-scale solar-system renderer and as part of that I need to draw the scene in multiple depth “slices”. For each slice, I scale the scene objects relative to the camera to bring them closer (within depth buffer precision), and make the frustum near/far fit the objects for the slice. I draw the slices from back to front, and between slices I need to clear to depth buffer so that close-up objects are not occluded by far-away objects (whose depths are in the same range).

However, when I try to just insert a glClear( GL_DEPTH_BUFFER_BIT ) between depth slices, it doesn't seem to be working. Far-away objects are occluding the close-up objects. Is it valid to clear the depth buffer (of the same framebuffer) more than once per frame (and I have a bug somewhere)? Or do I have to use a separate framebuffer for each depth pass and then composite them together? (yuck) Any tips for how to effectively “reset” the depth buffer multiple times per frame?

Edit: I think I found the bug in my code. I was using a queue of render commands, which were all being submitted at the end of the frame (after both calls to glClear()). I'm still interested if there are better ways to clear the depth often.

Advertisement

Have you tried reversed Z buffer? Never did myself, but i would be optimistic no slicing / multiple passes would be needed at all.

JoeJ said:

Have you tried reversed Z buffer? Never did myself, but i would be optimistic no slicing / multiple passes would be needed at all.

Not yet, it's not supported by the earlier OpenGL versions I'm stuck on. I have doubts that slicing could be avoided for solar-scale scenes.

Consider a scene where you are standing on a planet surface, with small objects in the foreground, and a large planet 1 billion meters away is visible in the sky. There's just not enough depth precision in 32-bit floats to handle that sort of large depth ratio and render both the planet and foreground objects accurately. I think there will be Z-fighting of the planet's front/back faces. I guess you could cull back faces and mostly avoid that, but the multi-slice rendering is pretty easy to implement and works well, and guarantees there will be no Z-fighting.

Much harder is dealing with positions of objects without double precision (I am using a tree of reference frames that gets traversed to calculate the unit vector and double-precision distance to each object in the camera's frame). The vector and distance are used to offset each object's transform relative to the camera, and scaling the far-away objects is as simple as scaling the distance and transform matrix.

Aressera said:
I think there will be Z-fighting of the planet's front/back faces. I guess you could cull back faces and mostly avoid that

Yeah, that's part of how i imagine it could work.
I mean, if you have realistic scales, other planets are just a dot. It's rings or moons would not be visible at all, and Z errors would not matter.
Having two suns might be a bigger problem, but even there it would not matter if their depth order jitters because they are both just bright white.
So an infinite far plane should handle such scales eventually.

But idk how much various projection setups and tricks help with distant, detailed stuff on the same planet.

Aressera said:
(I am using a tree of reference frames that gets traversed to calculate the unit vector and double-precision distance to each object in the camera's frame).

Interesting, because i plan to do the same for open world landscapes. But because i have a dense, flat world, i can just use a 2D regular grid of reference frames instead a tree.

The problem i see is not graphics, but the physics engine. If the camera changes reference frame, the origin of the simulation should become that frames center as well, so the sim remains at good precision too.
So we would need to scroll the whole simulation state, including cached contacts, avoiding a need to recompute acceleration structures.
I hope this works out. Interestingly, no physics engines seem to have build in support for such open world demands.

This reverse Z trick makes 24 bit depth buffers more precise, if you have clipControl I would advise using it since it switches the depth buffers logarithmic precision to a more linear one.
I know in D3D you are allowed to use a clear more often than once during a rendering commandlist but I doubt that they garentee that all commands in the pipeline will be flushed before you call this clear which might be causing your isseus. Have you tried looking at a frame debugger to see whats happenign with your commands? If you are using the core profile of OpenGL - from 3.2 up to 4.6 inclusive, you can use renderdoc to see whats going on

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

JoeJ said:

The problem i see is not graphics, but the physics engine. If the camera changes reference frame, the origin of the simulation should become that frames center as well, so the sim remains at good precision too.
So we would need to scroll the whole simulation state, including cached contacts, avoiding a need to recompute acceleration structures.
I hope this works out. Interestingly, no physics engines seem to have build in support for such open world demands.

Exactly, this is a big problem and one which I put a lot of effort into dealing with. The problem gets worse if you don't make the assumption that there is only one scene observer (which all implementations I've seen do). Multiple observers are necessary for true multiplayer, or possibly AI agents which need to navigate the scene far from the player. Imagine you send an automated space probe to the surface of another planet, similar to in the game Outer Wilds. With multiple viewpoints, you can't just shift the origin for the physics, because really there need to be multiple origins simulated simultaneously. AFAIK off-the-shelf physics engine don't support this, so I am lucky I already have built a custom rigid body physics engine where I can add support for this.

My approach is to just “alias” the various reference frames so that they all are simulated in the same overlapping floating-point space. Each physics object gets a pointer to the reference frame it resides within, and then I only do anything special when dealing with object interactions between objects in different frames. This includes collision detection, or when calculating distant forces (gravity). Everything else, like integration, is either done in local space, or operates only on velocities (constraint solving).

Aressera said:
My approach is to just “alias” the various reference frames so that they all are simulated in the same overlapping floating-point space. Each physics object gets a pointer to the reference frame it resides within, and then I only do anything special when dealing with object interactions between objects in different frames. This includes collision detection, or when calculating distant forces (gravity). Everything else, like integration, is either done in local space, or operates only on velocities (constraint solving).

I had proposed this to the dev of the physics engine : )

It's the only proper way i think. No need for scrolling, and most games nowadays are big. The extra cost to handle differing frames is small, constant, and causes no runtime spikes.

try forcefully finishing all rendering operations
with this you basically semaphoring the video card to your actual rendering code

-glClear( GL_DEPTH_BUFFER_BIT);

+glFlush();
+glClear( GL_DEPTH_BUFFER_BIT);
+glFlush();

After some better testing I have determined that clearing the depth buffer multiple times per frame is very slow, particularly on integrated GPU in fullscreen, where just commenting out the glClear() improves performance by a factor of 2 to 3 (though produces incorrect image).

I am going to instead try drawing a fullscreen quad at maximum depth with depth test GL_ALWAYS and color writes disabled. That will have less sync points with the GPU, should be pretty fast, and I can submit the whole scene as a single queue of commands.

Edit: fullscreen quad works but is slower than glClear() (makes sense that it would be hard to beat the driver at a basic task). I think it's just that the integrated GPU is pretty crappy and can't handle high fill rate and moderately heavy shaders without churning.

It is notable slower on anything. Even on modern cards.

This topic is closed to new replies.

Advertisement