A simple, interactive ASCII art of a spinning 3D donut in the terminal, implemented in Python.
- Python 3
- NumPy
- Keyboard
Install the dependencies using pip:
pip install numpy keyboard
Run the script via the terminal:
python colored_donut.py
- Zoom In: Up Arrow
- Zoom Out: Down Arrow
The spinning 3D donut animation involves fascinating mathematical logic, applying rotations in 3D space, and translating it into a 2D terminal view using ASCII characters.
In 3D graphics, rotating a point ((x, y, z)) around any axis involves trigonometric transformations. The code primarily applies rotations around the X and Z axes, denoted as "A" and "B" respectively in the code. The transformation in 3D coordinates post-rotation by angles A (around X-axis) and B (around Z-axis) can be represented using rotation matrices:
[ R_x(A) = \begin{bmatrix} 1 & 0 & 0 \ 0 & \cos A & -\sin A \ 0 & \sin A & \cos A \end{bmatrix} ] [ R_z(B) = \begin{bmatrix} \cos B & -\sin B & 0 \ \sin B & \cos B & 0 \ 0 & 0 & 1 \end{bmatrix} ]
In the code, these rotations are not applied simultaneously, but successively, resulting in the derivation:
x = (np.outer(cos_B * cos_phi + sin_A * sin_B * sin_phi, circle_x) - circle_y * cos_A * sin_B).T
y = (np.outer(sin_B * cos_phi - sin_A * cos_B * sin_phi, circle_x) + circle_y * cos_A * cos_B).T
z = ((K2 + cos_A * np.outer(sin_phi, circle_x)) + circle_y * sin_A).T
Here, np.outer() calculates the outer product of two arrays, effectively computing the results for all points simultaneously, enhancing computational efficiency.
Rendering Perspective To visualize the 3D model in a 2D terminal, a perspective projection step is implemented in the code, translating 3D points to 2D. The computation involves K1, K2, ooz (one over z for depth perception), and other variables. The consistent recalculations of sine and cosine values, as angles A and B change, provide the animated rotational effect, crafting a mesmerizing visualization of a 3D donut rotating in the 2D terminal space.
Ensure Python and pip are correctly installed and in your PATH. Adjust time.sleep() delay in the script if the animation speed is not suitable.
Inspired by the iconic "donut.c" code by Andy Sloane.
Contributions are welcome! <3
Made with ❤️ and Python.