RUST · 3D GRAPHICS & MODELING

blender-rs — Memory-Safe Rust Re-Architecture of the Blender 3D Creation Suite

blender-rs is a modular Rust port of Blender's core 3D geometry, mesh subdivision, dependency graph, and Cycles/EEVEE scene evaluation pipelines. It provides deterministic, thread-safe Rust crates for procedural 3D modeling, headless scene rendering, and glTF/USD asset processing without C/C++ memory bugs.

$ cargo add blender-rs
GitHub ↗
01 // Interactive Half-Edge Kernel & Rasterizer

3D BMesh Topology & Terminal Viewport Playground

Simulating blender_bmesh::BMesh + blender_app::ViewportRasterizer
2. Subdivision Passes (edge_split) 0 Passes
vpool (BMVert): 8
epool (BMEdge): 12
lpool (BMLoop): 24
fpool (BMFace): 6
Euler (χ = V - E + F): χ = 2 (Manifold)
CLI Command: blender --primitive cube
DRAG TO ORBIT // SCROLL TO ZOOM // DOUBLE-CLICK TO RESET CAMERA 60 FPS // TOPOLOGY VALIDATED
02 // Modular Rust Workspace

11-Crate Architecture & Subsystem Mapping

blender-bmesh 115 files // 6,086 LOC
Upstream: source/blender/bmesh

Non-manifold-capable half-edge polygon mesh kernel (BMVert, BMEdge, BMLoop, BMFace) with circular disk, radial, and face-loop cycles, Newell normals, Euler operators, and bevel/bisect/bridge/extrude/subdivide operators.

bm.face_create(&[v0, v1, v2, v3], None)?; bm.edge_split(edge_h, 0.5)?;
blender-mem 21 files // 662 LOC
Upstream: source/blender/blenlib/BLI_mempool.h

Generational slot allocator (MemPool<T>) and 64-bit Handle<T> indexing that replaces raw C pointers across cyclic BMesh topologies, guaranteeing zero use-after-free bugs with O(1) free-list reuse.

let h: Handle<BMVert> = pool.alloc(vert); assert!(pool.get(h).is_some());
blender-dna 172 files // 42,090 LOC
Upstream: source/blender/makesdna/DNA_*

Complete Rust type definitions for Blender's serialized DNA data schemas (DNA_mesh_types, DNA_object_types, DNA_scene_types, MeshElemFlags, and CustomDataType).

pub struct MeshElemFlags: u8 { const SELECT = 1 << 0; const SMOOTH = 1 << 4; }
blender-geom 13 files // 1,917 LOC
Upstream: source/blender/blenlib/intern/math_geom.cc

Hand-ported computational geometry kernels: flat-array median-split Bvh (raycasting & closest-point), pointerless 3D KdTree, ear-clipping triangulate_polygon_v2, monotone-chain convex_hull_v2, and barycentric/ray intersections.

let bvh = Bvh::new(&tris); let hit = bvh.ray_cast(orig, dir);
blender-math 57 files // 1,570 LOC
Upstream: source/blender/blenlib/BLI_math_*

SIMD-accelerated vectors, matrices, and quaternions powered by glam, alongside Bounds2D, BoundingBox, Garland-Heckbert Quadric decimation metrics, XPBD physics constraints, and Deriche/Van Vliet blur kernels.

pub use glam::{Mat3, Mat4, Quat, Vec2, Vec3, Vec4};
blender-io 419 files // 15,511 LOC
Upstream: source/blender/io/*

High-throughput mesh importers, exporters, and scene filter pipelines for Wavefront OBJ, Stanford PLY, STL, and Universal Scene Description (USD).

let obj_text = blender_io::export_obj(&scene.bmesh);
blender-obj 1 file // 327 LOC
Upstream: source/blender/io/wavefront_obj

Standalone zero-dependency Wavefront .obj parser and serializer supporting arbitrary n-gons, negative relative indices, vertex normals/UVs, and ear-clipping fan triangulation.

let mesh = blender_obj::parse_obj(src)?; let tris = mesh.triangulate();
blender-stl 1 file // 304 LOC
Upstream: source/blender/io/stl

Auto-detecting binary and ASCII .stl reader and writer with bit-identical [u32; 3] vertex welding (to_indexed / from_indexed) that normalizes signed zero (-0.0 == 0.0).

let stl = blender_stl::read_stl(&bytes)?; let (verts, tris) = stl.to_indexed();
blender-bridge 1 file // 142 LOC
Upstream: source/blender/blenkernel/intern/mesh_convert.cc

Lossless bidirectional topology conversion (obj_to_bmesh and bmesh_to_obj) preserving arbitrary n-gon face loops and verifying Euler characteristic invariants.

let bm = obj_to_bmesh(&obj)?; let roundtrip = bmesh_to_obj(&bm);
blender-app 3 files // 388 LOC
Upstream: source/creator

The blender CLI binary providing procedural primitive generation, multi-pass edge subdivision, Wavefront OBJ export, a 3D terminal Bresenham wireframe viewport, and automated benchmarking.

blender --primitive cube --subdivide 2 --viewport --export-obj out.obj
blender-cluster 5 files // 905 LOC
Upstream: Transpilation & Verification Tooling

AST call-graph clusterer and automated C/C++ to Rust subsystem verification harness tracking the 773 ported modules in PORTING_PROGRESS.json.

pub mod ast; pub mod cluster; pub mod verifier;
03 // Performance Telemetry

Empirical Benchmarks: blender-rs vs Upstream Blender 4.2 C/C++

Full BENCHMARKS.md Report ↗
Subsystem Crate Workload / Kernel blender-rs (Rust) Blender 4.2 (C/C++) Speedup & Safety Advantage
Memory Arena blender-mem MemPool<BMVert> 1M alloc + 50% free-list churn 14.2 ms 16.8 ms (BLI_mempool) 1.18x faster + Generational UAF safety
BMesh Subdivision blender-bmesh Default Cube + 3x edge_split + validate_topology 41.8 µs 46.5 µs (BM_mesh_create) 1.11x faster + Zero raw C pointers
BMesh UV Sphere blender-bmesh 64x32 UV Sphere (V=1,986, E=4,032, F=2,048) 312.4 µs 348.0 µs (BMO_op_uvsphere) 1.11x faster + Verified χ = 2 manifold
BVH Raycast blender-geom Bvh::new (200K tris) + 10K Möller–Trumbore rays 28.4 ms / 1.9 ms 34.1 ms / 2.2 ms (BLI_bvhtree) 1.20x faster + Flat 36B Vec<Node>
3D KD-Tree blender-geom KdTree::new (100K pts) + 10K find_nearest_n(16) 11.6 ms / 3.4 ms 15.2 ms / 4.1 ms (BLI_kdtree_3d) 1.31x faster + Pointerless 20B nodes
Polygon Ear-Clip blender-geom triangulate_polygon_v2 (1,000 concave 64-gons) 1.84 ms 2.05 ms (BLI_polyfill_2d) 1.11x faster + Collinear fallback
Binary STL Weld blender-stl Binary STL parse (100K tris) + to_indexed weld 8.7 ms 11.4 ms (io_mesh_stl) 1.31x faster + Bit-exact [u32; 3] hash
OBJ ↔ BMesh Bridge blender-bridge obj_to_bmesh + bmesh_to_obj (10K n-gon faces) 6.2 ms 7.9 ms (io_wavefront_obj) 1.27x faster + Lossless n-gon cycles
04 // Reproducible Workflows

CLI & Rust SDK Quickstart

TERMINAL // CLI VIEWPORT & BENCHMARK
# Clone and run the full 11-crate test suite
git clone https://github.com/bhubbard/blender-rs.git
cd blender-rs
cargo test --workspace --release

# Render a subdivided cube in the 3D Bresenham terminal viewport
cargo run --release -p blender-app --bin blender -- \
  --primitive cube --subdivide 1 --viewport

# Generate a UV sphere and export to Wavefront OBJ
cargo run --release -p blender-app --bin blender -- \
  --primitive sphere --export-obj sphere.obj

# Run the end-to-end BMesh + subdivision + OBJ export benchmark
cargo run --release -p blender-app --bin blender -- --benchmark
RUST SDK // HALF-EDGE BMESH & BVH RAYCAST
use blender_bmesh::BMesh;
use blender_geom::bvh::Bvh;
use blender_math::Vec3;

fn main() -> anyhow::Result<()> {
    // 1. Construct a quad in the generational BMesh kernel
    let mut bm = BMesh::new();
    let v0 = bm.vert_create(Some(Vec3::new(0.0, 0.0, 0.0)), None);
    let v1 = bm.vert_create(Some(Vec3::new(2.0, 0.0, 0.0)), None);
    let v2 = bm.vert_create(Some(Vec3::new(2.0, 2.0, 0.0)), None);
    let v3 = bm.vert_create(Some(Vec3::new(0.0, 2.0, 0.0)), None);
    let face = bm.face_create(&[v0, v1, v2, v3], None)?;

    // 2. Split an edge via Euler operator (promotes quad to 5-gon)
    let first_edge = bm.epool.iter().next().unwrap().0;
    bm.edge_split(first_edge, 0.5)?;
    bm.recalc_face_normals();
    assert_eq!(bm.fpool.get(face).unwrap().len, 5);

    // 3. Raycast triangles with blender_geom::bvh::Bvh
    let tri = [Vec3::ZERO, Vec3::X * 2.0, Vec3::Y * 2.0];
    let bvh = Bvh::new(&[tri]);
    let hit = bvh.ray_cast(Vec3::new(0.5, 0.5, 5.0), -Vec3::Z).unwrap();
    assert!((hit.t - 5.0).abs() < 1e-6);
    Ok(())
}