Metadata-Version: 2.4
Name: aiden3drenderer
Version: 1.7.2
Summary: A lightweight 3D wireframe renderer built from scratch using Pygame
Home-page: https://github.com/AidenKielby/3D-mesh-Renderer
Author: Aiden
Author-email: headstone.yt@gmail.com
Keywords: 3d,renderer,wireframe,pygame,mesh,3d-rendering,procedural,terrain,physics,opengl,rasterizer,projection,camera,computer-graphics,3d-engine
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: pygame>=2.6.0
Requires-Dist: numpy>=2.4.2
Requires-Dist: opencv-python>=4.13.0.90
Requires-Dist: moderngl>=5.12.0
Requires-Dist: pillow>=12.1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

[![PyPI Downloads](https://static.pepy.tech/personalized-badge/aiden3drenderer?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/aiden3drenderer)
[![PyPI version](https://img.shields.io/pypi/v/aiden3drenderer?color=green)](https://pypi.org/project/aiden3drenderer/)
[![Python Versions](https://img.shields.io/pypi/pyversions/aiden3drenderer)](https://pypi.org/project/aiden3drenderer/)
![Per Month](https://img.shields.io/pypi/dm/aiden3drenderer)
[![License: MIT](https://img.shields.io/pypi/l/aiden3drenderer)](https://github.com/AidenKielby/3D-mesh-Renderer/blob/main/LICENSE)
[![PyPI status](https://img.shields.io/pypi/status/aiden3drenderer)](https://pypi.org/project/aiden3drenderer/)
[![GitHub stars](https://img.shields.io/github/stars/AidenKielby/3D-mesh-Renderer?style=social)](https://github.com/AidenKielby/3D-mesh-Renderer/stargazers)
[![Last commit](https://img.shields.io/github/last-commit/AidenKielby/3D-mesh-Renderer)](https://github.com/AidenKielby/3D-mesh-Renderer/commits/main)

# Aiden3DRenderer
A lightweight but capable 3D renderer for Python + Pygame with custom projection math, first-person camera controls, procedural geometry, OBJ support, basic physics, and an optional GPU raster path.

## Feature List (Clickable)

Every item below links to its explanation section.

- [Custom 3D Projection](#custom-3d-projection) - Projection pipeline implemented manually (no external 3D engine).
- [First-Person Camera (6-DOF)](#first-person-camera-6-dof) - Mouse look + keyboard movement with speed control.
- [15+ Procedural Shape Generators](#15-procedural-shape-generators) - Mountains, cities, fractals, knots, and more.
- [Real-Time Rendering](#real-time-rendering) - Designed for responsive live rendering workflows.
- [Animated Terrains](#animated-terrains) - Time-based procedural surfaces.
- [Extensible Shape API](#extensible-shape-api) - Register your own shapes with `@register_shape`.
- [Multiple Object Support](#multiple-object-support) - Render multiple meshes/shapes in one scene.
- [Per-Shape Colors](#per-shape-colors) - Custom colors for polygon/raster workflows.
- [Simple Physics Engine](#simple-physics-engine) - Basic forces and collisions for spheres/planes/camera.
- [OBJ Loading](#obj-loading) - Load and render `.obj` files with triangulation and UV parsing.
- [Rasterization Paths](#rasterization-paths) - CPU fill path + GPU compute-shader raster path.
- [Three Render Modes](#three-render-modes) - `MESH`, `POLYGON_FILL`, and `RASTERIZE`.
- [Raster Debug Views](#raster-debug-views) - Depth and heat-map diagnostics.
- [Texture Mapping](#texture-mapping) - UV texture sampling in raster mode.
- [Multi-Texture Pipeline](#multi-texture-pipeline) - Multiple texture layers selectable per OBJ.
- [Runtime Shape Management](#runtime-shape-management) - Toggle built-in defaults while running.
- [Skybox Rendering](#skybox-rendering) - Generate cubemap skyboxes from UVs or cross atlas layouts.
- [Pause + Settings UI](#pause--settings-ui) - Tune mode, FOV, debug views, and lighting live.
- [Video Renderer (Experimental)](#video-renderer) - Render OBJ animation clips to video output.
- [macOS GPU Note](#macos-gpu-note) - Compute-shader limitation and VM workaround.

## Gallery

               Ripple Animation
        
        Ripple Effect
        
        Expanding waves from center
      
               Mandelbulb Fractal
        
        Mandelbulb Slice
        
        3D fractal cross-section

               Turning Spiral
        
        Turning Spiral
        
        Screw-like surface animation
      
               Simple City (laggy when solid render)
        
        Simple City
        
        Large procedural city terrain

               Tree Mesh
        
        Tree Mesh
        
        Wireframe OBJ rendering
      
               Tree Solid Render
        
        Tree Solid Render
        
        Filled rendering from same scene

               Colored Tree
        
        Colored Tree
        
        Per-shape color update showcase
      
               Physics Demo
        
        Physics Demo
        
        Collision and motion in scene

               Skull and Skybox
        
        Skull + Skybox
        
        OBJ + environment background
      
               Minecraft Boat Wireframe
        
        Minecraft Boat Wireframe
        
        Complex model wireframe preview

## Installation

```bash
pip install aiden3drenderer
```

Requirements:
- Python 3.11+
- Pygame 2.6.0+ (installed automatically)

## Quick Start

### Minimal Example

```python
from aiden3drenderer import Renderer3D, renderer_type

renderer = Renderer3D()
renderer.camera.position = [0, 0, 0]
renderer.render_type = renderer_type.POLYGON_FILL
renderer.run()
```

### Looped Run Example

Use `loopable_run()` when you want to integrate custom game logic each frame.

```python
from aiden3drenderer import Renderer3D, renderer_type

renderer = Renderer3D()
renderer.render_type = renderer_type.POLYGON_FILL

while True:
    # Custom logic here
    renderer.loopable_run()
```

### Runtime Pause/Settings

Press `Esc` during `run()` to open the runtime menu.

You can:
- Switch render mode (`MESH` / `POLYGON_FILL` / `RASTERIZE`)
- Toggle raster debug views (depth/heat)
- Adjust FOV
- Adjust lighting strictness
- Toggle OBJ render mode handling

## Feature Explanations

### Custom 3D Projection
The renderer uses a full world-to-screen pipeline implemented in Python:
1. Translate vertices into camera space.
2. Apply yaw/pitch/roll rotations.
3. Perspective divide by depth with FOV scaling.
4. Map to screen coordinates.

No external 3D engine is required for the core projection math.

### First-Person Camera (6-DOF)
Camera movement is designed for interactive exploration:
- Movement: `W/A/S/D`, `Space`, `Left Shift`
- Speed boost: `Left Ctrl`
- Rotation: right mouse drag + arrow key nudging
- FOV tweak: mouse wheel

### 15+ Procedural Shape Generators
Built-in generators include mathematical and stylized surfaces such as:
- Mountain, canyon, pyramid, torus, sphere
- Mobius strip, megacity, mandelbulb slice
- Klein bottle, trefoil knot
- Animated waves/ripples/spirals/alien terrain/double helix

### Real-Time Rendering
The engine is designed for live rendering loops and interactive scenes. Typical scenes can run smoothly at real-time frame rates depending on selected mode and geometry complexity.

### Animated Terrains
Animated shapes use the `frame` parameter inside shape generators. This enables time-driven deformation without changing the API shape contract.

### Extensible Shape API
Create custom shapes using `@register_shape`.

```python
from aiden3drenderer import Renderer3D, register_shape
import pygame

@register_shape("My Plane", key=pygame.K_p, is_animated=False, color=(200, 255, 150))
def generate_plane(grid_size=40, frame=0):
    return [
        [(1, 1, 1), (2, 1, 1), (3, 1, 1)],
        [(1, 1, 2), (2, 1, 2), (3, 1, 2)],
        [(1, 1, 3), (2, 1, 3), (3, 1, 3)],
    ]

renderer = Renderer3D()
renderer.run()
```

Important shape rule:
- Return a rectangular matrix (`list[list[tuple | None]]`) where all rows have the same length.

### Multiple Object Support
You can render multiple objects at once by appending several shape/OBJ entries to the active scene list.

### Per-Shape Colors
Shapes can define explicit base colors in registration, which are respected in filled/raster workflows.

### Simple Physics Engine
Physics module supports basic rigid-body style interactions:
- Sphere objects
- Plane colliders
- Gravity/forces
- Sphere-sphere and sphere-plane collision handling
- Camera physics wrapper support

For a full example, see the [Physics](#physics) section below.

### OBJ Loading
OBJ workflow supports standard model loading with extra quality-of-life features:
- Load from file path
- Parse UV (`vt`) data for raster texturing
- Triangulate faces with more than 3 vertices
- Per-object offset and `texture_index` support

For full usage, see [OBJ Loading](#obj-loading).

### Rasterization Paths
Two fill/raster workflows are available:
- CPU software triangle filling (`POLYGON_FILL`)
- GPU compute-shader rasterization (`RASTERIZE`)

### Three Render Modes
Switch with `renderer.render_type`:
- `renderer_type.MESH`
- `renderer_type.POLYGON_FILL`
- `renderer_type.RASTERIZE`

### Raster Debug Views
When using `RASTERIZE` mode:
- `toggle_depth_view(True)` for depth visualization
- `toggle_heat_map(True)` for heat-map diagnostics

### Texture Mapping
Apply texture sampling in raster mode using image files and OBJ UV coordinates.

### Multi-Texture Pipeline
Add multiple texture layers and assign each OBJ to one via `texture_index`.

```python
from aiden3drenderer import Renderer3D, obj_loader, renderer_type

renderer = Renderer3D(width=1000, height=800)
renderer.render_type = renderer_type.RASTERIZE
renderer.using_obj_filetype_format = True

renderer.add_texture_for_raster("./assets/model1.png")  # index 0
renderer.add_texture_for_raster("./assets/model2.png")  # index 1

obj1 = obj_loader.get_obj("./assets/model1.obj", texture_index=0)
obj2 = obj_loader.get_obj("./assets/model2.obj", texture_index=1, offset=(6, 0, 0))

renderer.vertices_faces_list.append(obj1)
renderer.vertices_faces_list.append(obj2)
renderer.run()
```

### Runtime Shape Management
Enable or disable built-in shape set at runtime:

```python
renderer = Renderer3D(load_default_shapes=False)
renderer.set_use_default_shapes(True)
```

### Skybox Rendering
Skyboxes can be generated from:
- Explicit cubemap UV mappings
- Cross-layout atlas images via `generate_cross_type_cubemap_skybox(...)`

### Pause + Settings UI
`Esc` opens a pause/settings UI while running. Use it for fast iteration without restarting your app.

### Video Renderer
The package includes an experimental OBJ-to-video renderer:
- Uses the same projection concepts as live renderer
- Supports per-object transforms and rotation rates
- Suitable for simple pre-rendered clips

More details in [Video Renderer](#video-renderer).

### macOS GPU Note
`RASTERIZE` mode requires OpenGL 4.3 compute shaders, which are not available natively on macOS.
Use `MESH`/`POLYGON_FILL` on macOS, or see [VM Workaround for macOS](#vm-workaround-for-macos).

## Renderer Modes and Debugging

```python
from aiden3drenderer import Renderer3D, renderer_type

renderer = Renderer3D()
renderer.render_type = renderer_type.RASTERIZE
renderer.set_texture_for_raster("./assets/alloy_forge_block.png")
renderer.toggle_depth_view(True)
renderer.run()
```

## Creating Custom Shapes

Shape functions must return a rectangular vertex matrix. Jagged rows can cause `IndexError` during mesh traversal.

### Advanced Shape Example

```python
from aiden3drenderer import Renderer3D, register_shape
import pygame

@register_shape("My Pyramid", key=pygame.K_p, is_animated=False)
def generate_pyramid(grid_size=40, frame=0):
    matrix = []
    center = grid_size / 2

    for x in range(grid_size):
        row = []
        for y in range(grid_size):
            dx = abs(x - center)
            dy = abs(y - center)
            max_dist = max(dx, dy)
            height = max(0, 10 - max_dist)
            row.append((x, height, y))
        matrix.append(row)

    return matrix

renderer = Renderer3D()
renderer.run()
```

## Physics

### About

Physics in Aiden3DRenderer is intentionally lightweight and extensible.

You can:
- Create sphere and plane physics objects
- Apply forces and impulses
- Simulate collisions
- Attach a physics camera
- Manage everything through `PhysicsObjectHandler`

### Example: Two Colliding Spheres

```python
from aiden3drenderer import Renderer3D, physics, renderer_type


def main():
    renderer = Renderer3D(width=1000, height=1000, title="My 3D Renderer")

    shape = physics.ShapePhysicsObject(renderer, "sphere", (0, 0, 0), (100, 0, 0), 5, 20, 20)
    shape.add_forces((-0.7, 0, 0))
    shape.anchor_position = [20, 0, 0]

    shape1 = physics.ShapePhysicsObject(renderer, "sphere", (0, 0, 0), (50, 0, 0), 5, 10, 20)
    shape1.add_forces((0.7, 0, 0))
    shape1.anchor_position = [0, 0, 0]

    obj_handler = physics.PhysicsObjectHandler()
    obj_handler.add_shape(shape)
    obj_handler.add_shape(shape1)

    renderer.set_starting_shape(None)
    renderer.camera.position = [0, 0, 0]
    renderer.render_type = renderer_type.POLYGON_FILL

    while True:
        obj_handler.handle_shapes()
        renderer.loopable_run()


if __name__ == "__main__":
    main()
```

### Example: Balls in a Box + Camera Physics

```python
from aiden3drenderer import Renderer3D, physics, renderer_type


def main():
    renderer = Renderer3D(width=1000, height=1000, title="My 3D Renderer")
    obj_handler = physics.PhysicsObjectHandler()

    plane_color = (200, 200, 200)
    plane_size = 28
    grid_size = 8

    obj_handler.add_plane(renderer, [0, -14, 0], (0, 0, 0), plane_color, plane_size, grid_size)
    obj_handler.add_plane(renderer, [-14, 0, 0], (0, 0, 90), plane_color, plane_size, grid_size)
    obj_handler.add_plane(renderer, [14, 0, 0], (0, 0, 90), plane_color, plane_size, grid_size)
    obj_handler.add_plane(renderer, [0, 0, -14], (90, 0, 0), plane_color, plane_size, grid_size)
    obj_handler.add_plane(renderer, [0, 0, 14], (90, 0, 0), plane_color, plane_size, grid_size)

    ball_color = (100, 100, 255)
    ball_radius = 4
    ball_mass = 2.5
    ball_grid = 8

    ball1 = physics.ShapePhysicsObject(renderer, "sphere", (0, 0, 0), ball_color, ball_radius, ball_mass, ball_grid)
    ball1.anchor_position = [0, 0, 0]

    ball2 = physics.ShapePhysicsObject(renderer, "sphere", (0, 0, 0), ball_color, ball_radius, ball_mass, ball_grid)
    ball2.anchor_position = [9, 0, 0]

    gravity = (0, -0.18, 0)
    ball1.add_forces((1, 0, 1))

    camera = physics.CameraPhysicsObject(renderer, renderer.camera, 1, 10)
    obj_handler.add_camera(camera)

    obj_handler.add_shape(ball1)
    obj_handler.add_shape(ball2)

    renderer.set_starting_shape(None)
    renderer.render_type = renderer_type.POLYGON_FILL
    renderer.camera.base_speed = 1.2

    while True:
        ball1.add_forces(gravity)
        ball2.add_forces(gravity)
        camera.add_forces(tuple(v * 100 for v in gravity))
        obj_handler.handle_shapes()
        renderer.loopable_run()


if __name__ == "__main__":
    main()
```

## OBJ Loading

### Example

```python
from aiden3drenderer import Renderer3D, obj_loader, renderer_type


def main():
    renderer = Renderer3D(width=1000, height=1000, title="My 3D Renderer")

    renderer.current_shape = None
    renderer.camera.position = [0, 0, 0]
    renderer.render_type = renderer_type.POLYGON_FILL
    renderer.using_obj_filetype_format = True

    obj = obj_loader.get_obj("./assets/alloy_forge_block.obj", texture_index=0)
    renderer.vertices_faces_list.append(obj)

    renderer.run()


if __name__ == "__main__":
    main()
```

### Notes

- `obj_loader.get_obj(path, texture_index, offset=(x, y, z))` supports per-object texture selection and world-space offset.
- N-gon faces are triangulated automatically.
- UV coordinates (`vt`) are parsed for texture mapping in raster mode.
- Cross-layout skybox helper: `generate_cross_type_cubemap_skybox(radius, img_path)`.

## Video Renderer

A lightweight experimental renderer for creating video clips from OBJ scenes.

### Basic Usage

```python
from aiden3drenderer.video_renderer import VideoRenderer3D, VideoRendererObject

obj = VideoRendererObject("assets/alloy_forge_block.obj")
obj.rotations_per_seccond = [10, 25, 0]
obj.rotation = [0, 0, 0]

vr = VideoRenderer3D(width=800, height=600, fps=30, shapes=[obj])
vr.render("out.avi", duration_s=5, verbose=True)
```

### Multiple Objects

```python
from aiden3drenderer.video_renderer import VideoRenderer3D, VideoRendererObject

o1 = VideoRendererObject("assets/model1.obj")
o1.rotations_per_seccond = [0, 40, 0]

o2 = VideoRendererObject("assets/model2.obj")
o2.rotations_per_seccond = [10, 0, 5]
o2.anchor_pos = [4, 0, 8]

vr = VideoRenderer3D(width=1200, height=800, fps=24, shapes=[o2, o1])
vr.render("multiples.avi", duration_s=10, verbose=True)
```

Tips:
- Keep resolution/FPS moderate while this module is still being optimized.
- Minor seam/overdraw artifacts are known limitations at the moment.

## macOS GPU Note

GPU `RASTERIZE` mode needs GL 4.3 compute shaders, which are unavailable on native macOS drivers.

## VM Workaround for macOS

- [Install UTM](https://mac.getutm.app)
- [Download Ubuntu ISO](https://ubuntu.com/download/desktop)
- Create a Linux VM in UTM
- Install Python:

```bash
sudo apt update
sudo apt install python3.11
python3 --version
sudo apt install python3-pip
```

Then install the package inside the VM:

```bash
pip install aiden3drenderer
```

## Controls

### Camera Movement
- `W/A/S/D` - Move forward/left/backward/right
- `Space` - Move up
- `Left Shift` - Move down
- `Left Ctrl` - Speed boost (2x)
- Mouse wheel - Adjust camera FOV
- Arrow keys - Fine pitch/yaw adjustment
- Right mouse + drag - Look around

### Terrain Selection
- `1` - Mountain terrain
- `2` - Animated sine waves
- `3` - Ripple effect
- `4` - Canyon valley
- `5` - Stepped pyramid
- `6` - Spiral surface
- `7` - Torus
- `8` - Sphere
- `9` - Mobius strip
- `0` - Megacity
- `Q` - Alien landscape
- `E` - Double helix
- `R` - Mandelbulb slice
- `T` - Klein bottle
- `Y` - Trefoil knot

### Other
- `Escape` - Open/close pause menu in `run()` mode

## Terrain Descriptions

### Static Terrains

**Mountain** (`1`) - Smooth parabolic mountain with radial falloff.

**Canyon** (`4`) - U-shaped valley with sinusoidal variation.

**Pyramid** (`5`) - Stepped pyramid using Chebyshev distance.

**Torus** (`7`) - Classic donut shape from parametric equations.

**Sphere** (`8`) - UV sphere generated from spherical coordinates.

**Mobius Strip** (`9`) - Non-orientable surface with a single continuous side.

**Megacity** (`0`) - 80x80 procedural city (6400 vertices) with roads and building variation.

**Mandelbulb** (`R`) - 2D slice through a Mandelbulb-style fractal field.

**Klein Bottle** (`T`) - Non-orientable 4D-inspired surface projected into 3D.

**Trefoil Knot** (`Y`) - Tube mesh along a classic trefoil knot path.

### Animated Terrains

**Waves** (`2`) - Multi-frequency flowing sine surface.

**Ripple** (`3`) - Expanding circular wave with amplitude decay.

**Spiral** (`6`) - Rotating polar-coordinate surface animation.

**Alien Landscape** (`Q`) - Mixed procedural terrain with craters, spikes, and pulsation.

**Double Helix** (`E`) - Twin strand structure with phase offset and animation.

## Technical Details

### 3D Projection Pipeline
1. World coordinates
2. Camera translation
3. Camera rotation (yaw/pitch/roll)
4. Perspective projection with FOV
5. Screen-space mapping

### Rotation Equations

Yaw (Y-axis):
```text
x' = x*cos(theta) + z*sin(theta)
z' = -x*sin(theta) + z*cos(theta)
```

Pitch (X-axis):
```text
y' = y*cos(phi) - z*sin(phi)
z' = y*sin(phi) + z*cos(phi)
```

Roll (Z-axis):
```text
x' = x*cos(psi) - y*sin(psi)
y' = x*sin(psi) + y*cos(psi)
```

### Culling
Vertices behind the camera (`z <= 0.1`) are culled (`None`) to avoid invalid perspective division and visual artifacts.

## Performance Notes

- Most built-in terrains are intended to be playable in real-time.
- Large scenes (especially filled modes) are heavier; `MESH` mode is best for maximum speed.
- `Megacity` is one of the largest defaults and a good stress test.

## API Reference

### Renderer3D

```python
from aiden3drenderer import Renderer3D

renderer = Renderer3D(width=1200, height=800)
renderer.run()
```

Useful methods and 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_format`
- `vertices_faces_list`
- `lighting_strictness`

### Camera

```python
from aiden3drenderer import Renderer3D

renderer = Renderer3D()
camera = renderer.camera

print(camera.position)   # [x, y, z]
print(camera.rotation)   # [pitch, yaw, roll]
print(camera.speed)
print(camera.base_speed)
```

### register_shape Decorator

```python
@register_shape(name, key=None, is_animated=False, color=None)
def generate_function(grid_size=40, frame=0):
    return matrix
```

Expected return type:
- `list[list[tuple[float, float, float] | None]]` (rectangular matrix)

## Package Structure

```text
aiden3drenderer/
|-- __init__.py
|-- renderer.py
|-- camera.py
|-- obj_loader.py
|-- physics.py
|-- shapes.py
`-- video_renderer.py

examples/
|-- basic_usage.py
|-- custom_shape_example.py
|-- obj_example.py
`-- physics_test.py
```

## Development

### Run from Source

```bash
git clone https://github.com/AidenKielby/3D-mesh-Renderer
cd 3D-mesh-Renderer
pip install -e .
python examples/basic_usage.py
```

### Build + Publish

```bash
pip install build twine
python -m build
python -m twine upload dist/*
```

## Credits

Created by Aiden.
Procedural terrain ideas were AI-assisted in places; core renderer/projection/camera and package engineering are authored manually.

## License

MIT
