A real-time 3D function visualizer with a plug-and-play GPU pipeline—write simple compute shaders to create custom effects without dealing with complex rendering internals.
Project description
Aiden3DRenderer
Interactive 3D playground for learning math, Python, and GPU shaders from first principles.
No graphics background required. If you can write basic Python, you can build and understand 3D scenes here.
If this project teaches you something useful, please give it a star. It helps a ton and keeps this passion project growing.
A quick note
I built this because I wanted 3D graphics to feel less "mystical" and more hands-on. So instead of hiding the pipeline behind a giant engine, this project keeps the core ideas visible: projection math, shape generation, shader logic, and simulation.
If you are learning, tinkering, or teaching with this repo, that is exactly what it was made for.
Who is this for?
- Math/CS students who want to visualize 3D functions by writing one Python function.
- Python learners who want a visual project with instant feedback instead of only terminal output.
- Aspiring graphics developers who want to write a first GLSL (OpenGL Shader Lanuage) shader with a plug-and-play setup.
Gallery
|
Ripple Surface |
Animated Spiral |
|
Physics Playground |
Rasterized Skull |
Why people love this project
- Built from scratch in Python for education: the projection pipeline is implemented manually so you can read it and understand it.
- You can visualize almost any mathematical surface by writing one function with
@register_shape. - You can write GLSL compute/post shaders without heavy engine boilerplate.
- Includes camera controls, OBJ loading, texture mapping, and a compact physics system for experimentation.
Start in 60 seconds
pip install aiden3drenderer
from aiden3drenderer import Renderer3D, renderer_type
renderer = Renderer3D()
renderer.render_type = renderer_type.POLYGON_FILL
renderer.run()
Visualize any math function
You define a shape by returning a rectangular matrix of (x, y, z) tuples. Decorate the function with @register_shape, run, and your shape appears in the scene.
Example 1: Animated ripple
import math
from aiden3drenderer import register_shape
@register_shape("Ripple", is_animated=True, color=(150, 180, 255))
def ripple(grid_size=48, frame=0):
matrix = []
half = grid_size / 2
for i in range(grid_size):
row = []
for j in range(grid_size):
x = (i - half) / (grid_size / 8)
y = (j - half) / (grid_size / 8)
r = math.hypot(x, y) + 1e-6
z = math.sin(3.0 * r - frame * 0.12) / (1.0 + r)
row.append((x, z, y))
matrix.append(row)
return matrix
Example 2: Gaussian hill
import math
from aiden3drenderer import register_shape
@register_shape("Gaussian Hill", is_animated=False, color=(220, 220, 220))
def gaussian_hill(grid_size=48, frame=0):
matrix = []
half = grid_size / 2
for i in range(grid_size):
row = []
for j in range(grid_size):
x = (i - half) / (grid_size / 6)
y = (j - half) / (grid_size / 6)
z = math.exp(-(x * x + y * y))
row.append((x, z, y))
matrix.append(row)
return matrix
Example 3: Parametric torus
import math
from aiden3drenderer import register_shape
@register_shape("Torus", is_animated=False, color=(230, 180, 150))
def torus(grid_size=48, frame=0, R=1.5, r=0.45):
matrix = []
for i in range(grid_size):
theta = (i / grid_size) * 2 * math.pi
row = []
for j in range(grid_size):
phi = (j / grid_size) * 2 * math.pi
x = (R + r * math.cos(phi)) * math.cos(theta)
y = r * math.sin(phi)
z = (R + r * math.cos(phi)) * math.sin(theta)
row.append((x, y, z))
matrix.append(row)
return matrix
Your first shader in 5 minutes
This is a headline feature: write a small GLSL compute shader, plug it into CustomShader, and run it.
Step 1: Write GLSL
#version 430
layout(local_size_x = 8, local_size_y = 8) in;
layout(std430, binding = 0) buffer pixels {
vec4 data[];
};
uniform uint width;
uniform float time;
void main() {
uint x = gl_GlobalInvocationID.x;
uint y = gl_GlobalInvocationID.y;
uint idx = y * width + x;
float u = float(x) / float(width);
data[idx] = vec4(u, 0.5 + 0.5 * sin(time + u * 10.0), 0.25, 1.0);
}
Step 2: Dispatch from Python
from aiden3drenderer import CustomShader
shader_src = """#version 430
layout(local_size_x = 8, local_size_y = 8) in;
layout(std430, binding = 0) buffer pixels { vec4 data[]; };
uniform uint width;
uniform float time;
void main(){
uint x = gl_GlobalInvocationID.x;
uint y = gl_GlobalInvocationID.y;
uint idx = y * width + x;
float u = float(x) / float(width);
data[idx] = vec4(u, 0.5 + 0.5*sin(time + u*10.0), 0.25, 1.0);
}
"""
cs = CustomShader(shader_src, context=renderer.ctx)
cs.set_buffer("pixels", renderer.width * renderer.height, element_size=16)
cs.write_to_uniform("width", renderer.width)
cs.write_to_uniform("time", 0.0)
groups_x = (renderer.width + 7) // 8
groups_y = (renderer.height + 7) // 8
cs.compute_shader.run(groups_x, groups_y, 1)
pixels = cs.read_from_buffer("pixels", renderer.width * renderer.height, element_type="vec4")
That is enough to start building shader effects. For more, see docs/custom_shaders.md.
Physics playground (learn simulation by seeing it)
The physics module is intentionally lightweight and educational:
- sphere objects
- plane colliders
- gravity and custom forces
- sphere-sphere and sphere-plane collisions
- optional camera physics wrapper
Great for learning integration and collision response with immediate visual feedback.
Pick your path
Path A: Learn 3D math
- Start with a built-in shape.
- Write a custom
@register_shapefunction. - Animate it with
frame.
Path B: Learn Python through visuals
- Tweak shape loops and constants.
- Add multiple objects in one scene.
- Explore render modes and pause settings.
Path C: Learn GLSL shaders
- Copy the minimal shader above.
- Change colors and gradients.
- Add your shader to a scene as a post-processing step.
Full technical reference (moved to the bottom)
Everything is still here, just organized so beginners see the exciting part first.
Render modes
renderer_type.MESHrenderer_type.POLYGON_FILLrenderer_type.RASTERIZE
Debug views in RASTERIZE mode:
toggle_depth_view(True)toggle_heat_map(True)
Controls
Camera movement:
W/A/S/Dmove forward/left/backward/rightSpacemove upLeft Shiftmove downLeft Ctrlspeed boost- mouse wheel adjusts FOV
- right mouse drag look around
- arrow keys fine pitch/yaw
Terrain selection keys:
1mountain2animated waves3ripple4canyon5pyramid6spiral7torus8sphere9mobius strip0megacityQalien landscapeEdouble helixRmandelbulb sliceTklein bottleYtrefoil knot
Other:
Escopen/close pause menu inrun()mode
API quick reference
Core:
Renderer3Dregister_shaperenderer_typeobject_type
Useful renderer methods/attributes:
set_starting_shape(shape_name_or_none)set_use_default_shapes(bool)set_render_type(renderer_type.*)toggle_depth_view(bool)toggle_heat_map(bool)set_texture_for_raster(path)add_texture_for_raster(path)generate_cross_type_cubemap_skybox(radius, img_path)generate_cubemap_skybox(...)using_obj_filetype_formatvertices_faces_listlighting_strictnessentities
Feature docs
- API index: docs/api.md
- Usage guide: docs/usage.md
- Tutorials: docs/tutorials.md
- Renderer internals: docs/renderer.md
- Shapes and custom shape API: docs/shapes.md
- Custom shaders: docs/custom_shaders.md
- Physics: docs/physics.md
- OBJ loader: docs/obj_loader.md
- DAE loader: docs/dae_loader.md
- Entities: docs/entities.md
- Camera: docs/camera.md
- Video renderer: docs/video_renderer.md
OBJ loading notes
obj_loader.get_obj(path, texture_index=0, offset=(x, y, z))- N-gon faces are triangulated automatically.
- UV (
vt) data is parsed for texture mapping.
macOS note
RASTERIZE mode needs OpenGL 4.3 compute shaders, which are not available on native macOS drivers.
Development
Run from source:
git clone https://github.com/AidenKielby/3D-mesh-Renderer
cd 3D-mesh-Renderer/Aiden3DRenderer
pip install -e .
python examples/basic_usage.py
Build and publish:
pip install build twine
python -m build
python -m twine upload dist/*
Credits
Created by Aiden.
Some procedural terrains, and most documentation was AI-assisted; core renderer, projection pipeline, camera, and packaging work are authored manually.
Libraries Used:
- pygame (Main Window)
- numpy (Accelerated Math)
- opencv-python (Video Renderer)
- moderngl (Compute Shaders)
- pillow (Texture Loading)
- lxml (DAE loading)
License
APACHE 2.0
If this README helped you decide to try the project, a star genuinely helps this indie project reach more learners.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aiden3drenderer-1.12.14.tar.gz.
File metadata
- Download URL: aiden3drenderer-1.12.14.tar.gz
- Upload date:
- Size: 819.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28876f773458e637efa0d76157c13a6f7d7d83376eb67bb11bdd96a46118ee96
|
|
| MD5 |
ceb3d49ad963ee983c051a3e876d37a2
|
|
| BLAKE2b-256 |
a6957e9a7bd32b665651acd8857c9955ef8e5e77fb00690b63796248949037a3
|
File details
Details for the file aiden3drenderer-1.12.14-py3-none-any.whl.
File metadata
- Download URL: aiden3drenderer-1.12.14-py3-none-any.whl
- Upload date:
- Size: 814.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1806cabad7f85d82b1072e138d9767b5670bd8c7aa2a4bf4c6ab1771473fdf66
|
|
| MD5 |
471c3d62f81b8abd3b751f35c20fa1d7
|
|
| BLAKE2b-256 |
df93e506ffa788a7a830346a7b2b5d8b7894d1b5fa4c266d681f445e3d2fad45
|