Asia/Manila
Projects

3D Rendering with ASCII in Terminal

image
April 28, 2025
This project explores the mathematical foundations of 3D rendering implemented entirely in ASCII characters within a terminal environment. By leveraging fundamental concepts from linear algebra and computer graphics, we create a dynamic 3D visualization system that runs in any terminal. The rotation matrix allows us to manipulate our viewing angle from a camera, using basic matrix multiplication we can transform our perspective. Let RR be a rotation matrix: R=(1000cos(θ)sin(θ)0sin(θ)cos(θ))(1)R = \begin{pmatrix} 1 & 0 & 0 \\ 0 & \cos(\theta) & -\sin(\theta) \\ 0 & \sin(\theta) & \cos(\theta) \end{pmatrix} \tag{1} On a 3D environment, let (x,y,z)(x, y, z) be the position of the camera. Let CC be a 3×13 \times 1 matrix containing these positions: C=(xyz)(2)C = \begin{pmatrix} x \\ y \\ z \end{pmatrix} \tag{2} We obtain the positions xx', yy', and zz' which represent the transformed positions from CRCR: CR=(xyz)(1000cos(θ)sin(θ)0sin(θ)cos(θ))=(xyz)(3)CR = \begin{pmatrix} x \\ y \\ z \end{pmatrix} \begin{pmatrix} 1 & 0 & 0 \\ 0 & \cos(\theta) & -\sin(\theta) \\ 0 & \sin(\theta) & \cos(\theta) \end{pmatrix} = \begin{pmatrix} x' \\ y' \\ z' \end{pmatrix} \tag{3} This evaluates to: CR=(xycos(θ)zsin(θ)ysin(θ)+zcos(θ))=(xyz)(4)CR = \begin{pmatrix} x \\ y \cdot \cos(\theta) - z \cdot \sin(\theta) \\ y \cdot \sin(\theta) + z \cdot \cos(\theta) \end{pmatrix} = \begin{pmatrix} x' \\ y' \\ z' \end{pmatrix} \tag{4} This allows us to view from whichever angle we prefer—allowing us to have a seamless dynamic experience. In computer vision, we have multiple ways to capture depth. One of which is how we calculate disparities (differences) from a binocular lens. The greater the disparity the farther the object, and vice versa. In perspective projection, we take that concept and sort-of inverse that process. This allows us to create the illusion of a 3D world existing beyond your computer screen. Let zz be the depth (distance from camera) and ff the focal length of camera: f=1tan(θ2) where θ is the FOV in radians(5)f = \frac{1}{\tan\left(\frac{\theta}{2}\right)} \text{ where } \theta \text{ is the FOV in radians} \tag{5} Given the relationship of ff and θ\theta, we can actually use ff as our FOV factor that we use for most projection formulae. Now, given a point in the 3D plane, we can project this onto the 2D screen using the nature of the relationship of FOV and the actual 3D space. Hence: x=xzf(6)x' = \frac{x}{-z \cdot f} \tag{6} y=yzf(7)y' = \frac{y}{-z \cdot f} \tag{7} Since we're dealing with vertices, edges, and faces from our original objects we need a way to display these seamlessly. We use Bresenham's Line Algorithm to assist with this. This process occurs after we've calculated xx' and yy' from Perspective Projection (see 2.2.2). Given an initial point on the 2D screen (x0,y0)(x_0, y_0) and a terminal point (x1,y1)(x_1, y_1) we can draw a line by calculating the differences dxdx and dydy between such points: dx=x1x0(8)dx = x_1 - x_0 \tag{8} dy=y1y0(9)dy = y_1 - y_0 \tag{9} The algorithm efficiently determines which pixels to fill to create the appearance of a straight line between two points, making it ideal for rendering wireframe 3D models in ASCII. For any object with vertex Vx,y,zMV_{x,y,z} \in M where MM is the set of all vertices defined on the object. To allow for animations on the object, we translate such vertices by a certain additive numerical value dkd_k where kk is any axis xx, yy, or zz. We can translate VkV_k by the following formula: Vk:=Vk+dk(10)V_k := V_k + d_k \tag{10} This simple translation operation enables smooth animations and object movement within our 3D space. The rendering pipeline combines these mathematical concepts to create a real-time 3D ASCII renderer:
  1. Model Definition: 3D objects are defined as collections of vertices and edges
  2. Camera Transformation: Apply rotation matrices to achieve desired viewing angles
  3. Perspective Projection: Convert 3D coordinates to 2D screen coordinates
  4. Line Rendering: Use Bresenham's algorithm to draw edges between projected vertices
  5. ASCII Mapping: Convert pixel coordinates to terminal character positions
This approach demonstrates how fundamental mathematical principles can be applied to create engaging visual experiences even within the constraints of a text-based terminal environment. The project addresses several interesting challenges:
  • Performance Optimization: Minimizing computational overhead for real-time rendering
  • ASCII Art Mapping: Converting geometric shapes to meaningful ASCII representations
  • Terminal Compatibility: Ensuring consistent rendering across different terminal environments
  • Animation Smoothness: Implementing efficient frame-by-frame updates
The result is a compelling demonstration of how mathematical theory translates into practical computer graphics applications, all rendered beautifully in ASCII art.