4. Add a Near Clipping Plane To The Renderer
We mentioned earlier that we have three choices of when we can clip line segments.
- before projection (in 3D camera coordinates),
clip -> project -> viewport transformation -> rasterize - after projection (in the 2D image-plane),
project -> clip -> viewport transformation -> rasterize - after viewport transformation (in the 2D pixel-plane)
project -> viewport transformation -> clip -> rasterize
In the first option, we clip line segments in camera space so that they are within the camera's view volume. In the second option we clip projected line segments in the image-plane so that they are within the image-plane's view rectangle. In the third option, we clip transformed line segments in the pixel-plane so that they are within the pixel-plane's logical viewport.
In the previous renderer we used the second option to clip projected line segments in the camera's image-plane. But the following demonstration program shows that there is a problem with the clipping algorithm.
renderer_3\clients_r3\SomethingWrong_2.java
If a line segment crosses the plane of the camera (the plane z = 0), then the vertex that is behind the camera gets projected in front of the camera and then the line segment gets rasterized incorrectly.
In this renderer, we give the Camera's view volume a fifth clipping plane, a "near clipping plane". This clipping plane stops the view volume from reaching all the way to the camera at the origin of camera space. We will use this near clipping plane to prevent line segments from crossing the camera plane. For this near clipping plane, we will use the first clipping choice above; we will do the near plane clipping before the projection stage.
4.1 Renderer source code
The Java source code for this renderer is publicly available as a zip file.
Here is a link to the renderer's source code.
Download and unzip the source code to any convenient location in your computer's file system. The renderer does not have any dependencies other than the Java 11 (or later) JDK. Once you have downloaded and unzipped the distribution, you are ready to compile the renderer and run the renderer's (interactive) example programs.
There are three new files in the renderer.pipeline package,
NearClip.java,NearClip_Line.java,NearClip_Point.java.
The file Camera.java in the renderer.scene package is modified to
store the position value of the camera's near clipping plane. The files
Pipeline.java and Pipeline2.java are modified to put the new clipping
stage into the rendering pipeline. The clients are modified to allow the
near clipping plane to be moved and for near clipping to be turned off
and on.
4.2 Pipeline
Our pipeline has the following six stages.
v_0 ... v_n A Model's list of Vertex objects
\ /
\ /
|
| model coordinates (of v_0 ... v_n)
|
+-------+
| |
| P1 | Model-to-camera transformation (of the vertices)
| |
+-------+
|
| camera coordinates (of v_0 ... v_n)
|
/ \
/ \
/ \
| P2 | Near Plane Clipping (of each primitive)
\ /
\ /
\ /
|
| camera coordinates (of the near-clipped v_0 ... v_n)
|
+-------+
| |
| P3 | Projection transformation (of the vertices)
| |
+-------+
|
| image plane coordinates (of v_0 ... v_n)
|
/ \
/ \
/ \
| P4 | Clipping (of each primitive)
\ /
\ /
\ /
|
| image plane coordinates (of the clipped vertices)
|
+-------+
| |
| P5 | Viewport transformation (of the clipped vertices)
| |
+-------+
|
| pixel-plane coordinates (of the clipped vertices)
|
/ \
/ \
/ \
| P6 | Rasterization & anti-aliasing (of each clipped primitive)
\ /
\ /
\ /
|
| shaded pixels (for each clipped, anti-aliased primitive)
|
\|/
FrameBuffer.ViewPort
4.3 Near Clipping Plane
The near clipping plane algorithm is essentially the same parametric clipping algorithm used in the last renderer. But instead of clipping line segments in a plane with respect to four lines, we clip line segments in 3D camera space with respect to a plane that is parallel to the xy-plane.
If a Vertex from a Primitive has a z-coordinate that is greater than
the z-coordinate of the near plane, then that Vertex "sticks out" of the
front of the camera's view volume. This algorithm will clip the primitive
so that it is entirely in front of the near clipping plane.
Here is an outline of the clipping algorithm for line segments.
Process each LineSegment object using the following steps.
1) Test if the line segment does not need to be clipped, i.e., both
of its vertices are in front of the near plane. If this is the case,
then return the LineSegment object wrapped in an Optional object.
2) Test if the line segment should be "trivially rejected". A line
segment is "trivially rejected" if both of its vertices are behind
the near plane. If so, then return an empty Optional object
indicating that the line segment should not be rasterized into
the viewport.
3) If the line segment has been neither accepted nor rejected,
then it straddles the near plane and it needs to be clipped.
Return a clipped LineSegment object wrapped in an Optional
object.
4.4 Computing the Clipped Vertex
When we clip a line segment against the near plane, it is always the case that one endpoint of the line segment is in front of the plane and the other endpoint is behind the plane. In the following picture, assume that v0 is behind the clipping plane (z = -near) and v1 is in front of the plane. So v0 needs to be clipped off the line segment and replaced by a new vertex.
z = -near
|
(x0, y0, z0) = v0 |
\ |
\ |
\|
\
|\
| \
| \
| v1 = (x1, y1, z1)
|
+----------------+--------------------------> -z axis
0 |
|
Represent points p(t) on the line segment between v0 and v1 with
the following parametric equation.
p(t) = (1-t) * v0 + t * v1 with 0 <= t <= 1
We need to find the value of t when the line segment crosses the near plane.
Let v0 = (x0, y0, z0) and let v1 = (x1, y1, z1). The above parametric
equation can be written in its component form,
p(t) = (x(t), y(t), z(t)) = ((1-t)*x0+t*x1, (1-t)*y0+t*y1, (1-t)*z0+t*z1)
which give us these three component equations,
x(t) = (1-t) * x0 + t * x1,
y(t) = (1-t) * y0 + t * y1,
z(t) = (1-t) * z0 + t * z1, with 0 <= t <= 1.
Let the near clipping plane be z = n. We need to solve the equation n = z(t)
for t. So we need to solve
n = (1-t) * z0 + t * z1
for t. Here are a few algebra steps.
n = z0 - t * z0 + t * z1
n = z0 + t * (z1 - z0)
n - z0 = t * (z1 - z0)
t = (1 - z0)/(z1 - z0)
Let t0 denote the above value for t. With this value for t, we can
compute the x-coordinate and the y-coordinate of the new Vertex,
p(t0) = (x(t0), y(t0), n)
that replaces v0.
z = n
|
|
|
|
p(t0)=(x(t0), y(t0), n)
|\
| \
| \
| v1 = (x1, y1, z1)
|
+----------------+--------------------------> -z axis
0 |
|
Here is the algebra.
x(t0) = (1-t0) * x0 + t0 * x1
= x0 + t0 * (x1 - x0)
= x0 + (1 - z0)*((x1 - x0)/(z1 - z0))
y(t0) = (1-t0) * y0 + t0 * y1
= y0 + t0 * (y1 - y0)
= y0 + (1 - z0)*((y1 - y0)/(z1 - z0))
4.5 Why we need the near clipping plane
The camera's perspective view volume is usually drawn as in the following picture but this picture is misleading.

The camera's view volume is not just "in front" of the camera (along the negative z-axis), it also extends "behind" the camera (along the positive z-axis), the view volume is "double ended". Its profile in the yz-plane should look like this.
\ /
\ / image plane
\ / |
\ / |
\ / |
\ / |
+z-axis <--------+----------|--------> -z axis
/0\ -1
/ \ |
/ \ |
/ \ |
/ \ |
/ \
The camera sees objects on both sides of its double sided view frustum. The projection formulas,
x_p = -x_c / z_c
y_p = -y_c / z_c
z_p = -1
work on both sides of the camera plane, z = 0 (but they don't work for points on the camera plane). Those formulas will "project" points "behind" the camera onto the image plane, z = -1. But they turn every object behind the camera into an upside down and backwards image.
You can see this happen with renderer_3. In renderer_3, run either of the following two clients.
renderer_3\clients_r3\InteractiveModels_R3.java
renderer_3\clients_r3\InteractiveModelsAll_R3.java
The z-key makes the cow model move forwards (towards the camera) and backwards (away from the camera). Use the z-key to move the cow model towards the camera until it hits the camera, then passes through the camera, and then appears behind the camera, upside down and backwards.
Having the camera see behind itself is not useful. It makes it impossible to place the camera in the middle of a bunch of objects. All the objects, both in front and behind the camera, will be visible. If you placed a camera like this in a room, it will see all four sides of the room.
The easiest way to stop the camera from seeing behind itself is the near clipping plane. As long as the near clipping plane is placed on the negative z-axis, so it is in front of the camera, nothing behind the camera will be visible.
With renderer_4, you can, if you want, place the near plane on the positive z-axis. Try doing that with the following renderer_4 client program.
renderer_4\clients_r3\InteractiveModels_R4.java