Enable depth testing
Description
We have the shape of the cube in perspective, but we're seeing the wrong faces. Faces that should be hidden are rendered on top of faces that should be visible.
This is partially because when we perform the perspective divide, we're dividing all components of the position by their depth. Our coordinates end up being (x / z, y / z, z / z). All of our z coordinates are set to 1.0.
To fix this, we need to map the range of Z values we want to display onto the -1.0 to 1.0 range in the clipping plane. We can do this by adjusting our perspective transform. There is a detailed derivation for how this matrix was produced on OGLdev.
We also need to enable depth testing in OpenGL. Without depth testing, OpenGL will display whatever was rendered last in front of any other rendered object. Depth testing will store the Z value for each rendered fragment in the depth buffer. When another fragment would be rendered in the same spot, it will first check the depth buffer to see if anything is in front of it to decide whether it should be visible.
By default OpenGL will keep depth values that are less than the currently stored value, although it is possible to change this with glDepthFunc. We'll keep this default and assume that the Z axis is pointing into the screen, so that smaller values are closer than larger values. This is referred to as a left-handed coordinate space. We could change it to a right-handed space by either modifying the depth function or the perspective transform.
Screenshot
Commands
git clone git@github.com:atsheehan/iridium
cd iridium
git checkout fcf5e621c408c86389cace997ace3ca429e889ae
cargo run --release
Code Changes
Modified shaders/cube.vertGitHub
@@ -1,6 +1,6 @@11 #version 150
22
3- const float NEAR = 0.0;
3+ const float NEAR = 0.1;
44 const float FAR = 10000.0;
55
66 uniform vec3 position = vec3(2.0, 3.0, 6.0);
@@ -83,7 +83,7 @@8383 mat4 world_to_clip_transform =
8484 mat4(1.0, 0.0, 0.0, 0.0,
8585 0.0, 1.0, 0.0, 0.0,
86- 0.0, 0.0, 1.0, 0.0,
86+ 0.0, 0.0, (-NEAR - FAR) / (NEAR - FAR), 2.0 * FAR * NEAR / (NEAR - FAR),
8787 0.0, 0.0, 1.0, 0.0);
8888
8989 mat4 model_to_world_transform =
@@ -1,6 +1,6 @@1 #version 150
2
3- const float NEAR = 0.0;
4 const float FAR = 10000.0;
5
6 uniform vec3 position = vec3(2.0, 3.0, 6.0);
@@ -83,7 +83,7 @@83 mat4 world_to_clip_transform =
84 mat4(1.0, 0.0, 0.0, 0.0,
85 0.0, 1.0, 0.0, 0.0,
86- 0.0, 0.0, 1.0, 0.0,
87 0.0, 0.0, 1.0, 0.0);
88
89 mat4 model_to_world_transform =
@@ -1,6 +1,6 @@1 #version 150
2
3+ const float NEAR = 0.1;
4 const float FAR = 10000.0;
5
6 uniform vec3 position = vec3(2.0, 3.0, 6.0);
@@ -83,7 +83,7 @@83 mat4 world_to_clip_transform =
84 mat4(1.0, 0.0, 0.0, 0.0,
85 0.0, 1.0, 0.0, 0.0,
86+ 0.0, 0.0, (-NEAR - FAR) / (NEAR - FAR), 2.0 * FAR * NEAR / (NEAR - FAR),
87 0.0, 0.0, 1.0, 0.0);
88
89 mat4 model_to_world_transform =
Modified src/render.rsGitHub
@@ -78,6 +78,7 @@7878
7979 unsafe {
8080 gl::ClearColor(0.6, 0.4, 0.8, 1.0);
81+ gl::Enable(gl::DEPTH_TEST);
8182 }
8283
8384 Self {
@@ -95,7 +96,7 @@9596
9697 pub(crate) fn clear(&mut self) {
9798 unsafe {
98- gl::Clear(gl::COLOR_BUFFER_BIT);
99+ gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
99100 }
100101 }
101102
@@ -78,6 +78,7 @@78
79 unsafe {
80 gl::ClearColor(0.6, 0.4, 0.8, 1.0);
81 }
82
83 Self {
@@ -95,7 +96,7 @@95
96 pub(crate) fn clear(&mut self) {
97 unsafe {
98- gl::Clear(gl::COLOR_BUFFER_BIT);
99 }
100 }
101
@@ -78,6 +78,7 @@78
79 unsafe {
80 gl::ClearColor(0.6, 0.4, 0.8, 1.0);
81+ gl::Enable(gl::DEPTH_TEST);
82 }
83
84 Self {
@@ -95,7 +96,7 @@96
97 pub(crate) fn clear(&mut self) {
98 unsafe {
99+ gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
100 }
101 }
102