I kept wanting to expore how to turn a 3D scene into lines that can be plotted by a pen plotter. So here goes. I don't think I'm inventing anything new here, but I want to understand how it works.
Simple Cube Wireframe
Let's start by drawing a cube which rotates around its axes and plotting the corner points along with the wireframe lines between those points. Consider this the initial step in the project. Behind the scenes this involves a lot of math, including, but not limited to, matrix multiplication in 2-, 3- and 4-D (the latter to use Homogeneous coordinates), both parallel and projective camera transforms. I've already set up all this math once before for my CPU-based 3D renderer, so most of the work was to adapt the go code to JavaScript.
Critically, I want to accomplish a 3D look using only SVG elements, which is inherently a 2D display technoloyg. In fact, I will also ignore SVG render order for occlusion, and will do all of the math myself. So for the display to the right, I am doing the math in 3D, but rendering SVG lines and points in 2D.
A funny side-effect is that if you look at the animation long enough, your brain can flip its direction of perception, making it seem that the deeper points appear more shallow, which is kinda fun. This is inherent to wireframe-only rendering. I'll start dealing with occlusion in the next section.
t={{t}}
Hiding Invisible Faces
Next, I want to start drawing faces. Notice that some faces are pointing away from the camera, and I can use the vertex order of each polygon to decide which direction that face is pointing. The rule I came up is that a face is facing the camera only if its vertexes appear in a counter-clockwise order. In other words, a face points in the same direction as the cross product between any subsequent edges of that face, presented in counter-clockwise order.
The resulting render of a cube now looks stunning, I only get the faces that are visible, the other faces are not even attempted to be rendered. However, the choice to display a cube hides a bigger issue with this algorithm - occlusion.
t={{t}}
Face Occlusion
A cube is simple in that no visible face occludes any other face. Let's add another object to the scene to be rendered behind the cube. With the current approach, faces from the two objects are rendered on top of each other, occlusion is completely ignored. Time to work on a solution.
t={{t}}
I have to start looking at whether the projected edge line segments intersect. If so, I'll decide which line segment is in front of the other one, and use this information to deduce the points defining the polygon from the camera's viewpoint. There are several edge cases to consider. A face can end up being split into multiple display polygons. A face can be obstructed my multiple other faces, and finally, a face polygon can completely contain another face's polygon. My algorithm has to account for all of these.
t={{t}}