0
\$\begingroup\$

Are there common, tried and tested techniques for making sure that when displaying very large and very small objects, in a 3D environment, those objects don't display in front or behind each other?

The scenario I am thinking of is a small person object being closer to the camera than a single, large (for the sake of argument) wind mill arm. As the wind mill turns, the centre of the arm would pass in front and behind the person object's centre. However, depending on the position of the camera, the arm should only be shown as passing either behind or in front of the person object.

\$\endgroup\$
2
\$\begingroup\$

Yes. Modern 3D graphics use a per-fragment (essentially, per-pixel) depth buffer to handle these scenarios correctly.

Rendered geometry (your person, your windmill arm) passes through the transformation pipeline, ultimately arriving in screen space with a screen space depth (distance from the eye point) for every vertex. That depth is interpolated over the surface of the geometry along with other attributes during rasterization. Before a final fragment is written to the output, the fragments depth is compared with the existing value in the depth buffer. If the existing depth is closer to the eye than the depth of the fragment, the fragment isn't written (it would be "behind" something closer).

The specifics of the depth buffer values, comparisons, and writing process can be tweaked via your graphics API, but that's the basic behavior. It handles basically everything except translucent objects, which must further be sorted by depth front-to-back before being rendered (because you do want to see some portion of fragments behind transparent fragments).


Since it sounds like you need to implement this yourself, I'll talk briefly about how. You don't need access to the GPU to do it; if you're writing your 3D pipeline yourself you're already having to do basically all the same things. At some point in your pipeline you have transformed 3D coordinates for all your vertices. And you'll be rasterizing triangles formed by those vertices by interpolating across the surface of those triangles, so you can interpolate depth (Z) just like any other attribute.

A depth buffer is straightforward: it's a big array of floats, an array that is the same size as your rasterization target (color buffer). For example, float depthBuffer[640 * 480];.

At the start of a render frame, clear this entire buffer to 1.0f (or whatever you choose to be the "furthest" depth). Then, when rasterizing your triangles, before you write the final color for the triangle, check the interpolated depth of that pixel against the depth in the buffer for that pixel's coordinates:

if (depth[pixelY * frameBufferWidth + pixelX] > interpolatedDepth) {
  // no previously-written pixels were closer than this pixel
  framebuffer[pixelY * frameBufferWidth + pixelX] = finalColor;

  // update the depth buffer
  depth[pixelY * frameBufferWidth + pixelX] = interpolatedDepth
}

This can be adapted to ray-tracing renderers as well (there are several papers on ray-z-depth algorithms). If your custom 3D implementation is not rasterization based or otherwises uses some other technique than the above, you'll probably have to post more about it before anybody can provide a drop-in implementation of a depth buffer.

Note that any kind of sorting-only process is going to fail at some point, which is why we generally use the depth buffer approach in modern renderers (even modern software renderers). Sorting-only is basically a painter's algorithm, which has impossible cases which will always render incorrectly.

\$\endgroup\$
  • \$\begingroup\$ I'm really looking for something which can figure out how to depth order big and small objects because I don't have the option of the type of pipeline you describe. \$\endgroup\$ – Matt W Jul 13 '16 at 17:53
  • \$\begingroup\$ As far as I can tell that pipeline handles your scenario, so you could just implement that. But it's possible I'm not completely understanding your scenario. Could you add a picture of the scenario you're talking about? As far as I can visualize it from your description so far, it's not actually that complicated. \$\endgroup\$ – Josh Jul 13 '16 at 17:54
  • \$\begingroup\$ No, it's not complicated, I think. Unfortunately I don't have access to the GPU hardware so that sort of advanced pipeline isn't an option. I'm writing the 3D engine entirely myself. I guess it's a clever sorting mechanism that I'm looking for. The question becomes "this small object is essentially behind this big object but should be rendered in front because the whole of it is in front of part of the large object." \$\endgroup\$ – Matt W Jul 13 '16 at 18:01
  • \$\begingroup\$ Ah, you don't need the GPU hardware. A depth buffer is just a big array of floats, you can implement it pretty trivially, I updated the answer to show how. \$\endgroup\$ – Josh Jul 13 '16 at 18:09
  • 1
    \$\begingroup\$ @MattW So how are you actually drawing things in your renderer if you are never plot actual pixels? I'm really confused how your render is working. It would be extremely helpful if you would edit your original post to describe your rendering system, othewise you're just going to have a lot of people making guesses with the limited information you've provided, since it sounds like you're implementation differs significantly from what most graphics folks are familiar with. \$\endgroup\$ – Josh Jul 13 '16 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.