THKP

View Original

Rendering 3d From Scratch Chapter 7 - The Depth Buffer

I’ve put together everything we’ve built so far in a demo below. It’s very simple. It renders a few rectangular prisms, and you can move the camera around.

See this content in the original post

You might’ve noticed there’s a glaring issue. If you missed it, just rotate the camera around 360 degrees. This isn’t 3d at all! It’s just a bunch of polygons drawn in a seemingly random order! It’s trippy, but not what we’re going for.

So what is actually happening? To diagnose this, let’s think back about how an eye or camera works. Light comes into the eye after bouncing off of objects. But if some other object obscures a ray of light, that ray never reaches your eye, and therefore your eye never perceives it. This probably sounds silly, but this is why when you put some object behind another object, you no longer see it. In the example above, objects are simply rendering in whatever order they are executed. There’s nothing checking whether some “light ray” is obscured by an object in front of it.

Luckily, there’s a common solution to this problem known as a depth buffer. A depth buffer lives alongside your screen, and for every pixel you write to the screen, you also record the distance from your camera to the pixel in your depth buffer. Then, if you find yourself writing two pixels to the same spot on the screen, you simply compare the depths of the two pixels and throw out the one that’s further away.

We can accomplish all this in our code by modifying a few key places. First, we can update Pixel to store the distance from the camera:

See this content in the original post

Now let’s make a few mods to our ScreenBuffer:

Add a depth buffer to the screen. Depths can be initialized to some max value:

See this content in the original post

When setting a pixel, check its depth against the current depth and only write the pixel if it’s closer:

See this content in the original post

When we clear the screen, also clear the depth buffer:

See this content in the original post

Now we need to go back and actually set our depth when creating pixels. This requires a few steps. The first is to calculate the distance from our face vertices and the camera in our “draw” function. I’ll copy the whole draw method here and highlight the important sections with comments:

See this content in the original post

Then, in our scanline filling algorithm, as we’re interpolating coordinates across faces, we also have to interpolate the depth. I’ll copy those methods as well, but there’s only a few necessary updates to call out:

See this content in the original post

Once those changes have been slotted into place, our trippy faces should start behaving themselves. Feel free to try it yourself if you’re following along, but otherwise, we’ll put it all together in the next post.

We’ve now successfully drawn a 3d scene with simple primitives! This is a pretty huge step, but there’s a great deal more to learn. In the next chapter, I’ll finish up this toy example with a few niceties, and discuss potential next topics to take on.