Skip to content
markarenPublic

About

A cross-platform C++20 3D library with Python bindings and the high-level API of three.js.

Topics

Resources

Stars

971 stars

Watchers

17 watching

Forks

Repository files navigation

threepp

Build License: MIT Conan Center PyPI

A cross-platform C++20 3D library with the high-level API of three.js, and two backends behind one scene graph: portable OpenGL, and a deferred Vulkan renderer with ray-traced shadows, reflections, AO and GI.

On top of that: a scene editor, PhysX robot simulation, simulated sensors with ground-truth labels for synthetic data, hardware-in-the-loop flight with ArduPilot, and Python bindings on PyPI.

An Otter X sea drone in a digital twin of a waterfront in Ålesund
An Otter X sea drone under way in a digital twin of a real waterfront in Ålesund, Norway, modelled from Kartverket lidar and sea charts and rendered by the Vulkan backend: the water reflects the moored boats and the buildings ashore (the scene is not in the repository)

New here? Getting started walks through the concepts the library is built from: the scene graph, ownership and lifetimes, geometry and materials, lights, the frame loop, loaders and the two backends. The examples folder is the de-facto reference.

Features

three.js parity. The API follows three.js r129, with selected features from r186 on the OpenGL path (shadow filtering, environment and background controls, material fixes, the newer post-processing passes).

  • Mesh, InstancedMesh, Line, Points, Sprites, 2D/3D text (typeface.json and TTF)
  • The usual geometries, lights (including RectArea), cameras, raycasting, animation, morph targets and bones
  • Physical materials with transmission, alpha hash and alpha-to-coverage; PMREM environment maps and RoomEnvironment
  • Shadows, Water and Sky shaders, and Orbit, Trackball, Fly, Drag and Transform controls
  • EffectComposer with bloom, depth of field, GTAO, outline, FXAA and output passes
  • Loaders: glTF/GLB (with meshopt), OBJ/MTL, STL, COLLADA, SVG, URDF/xacro (no ROS needed), PNG/JPEG, DDS, WebP, HDR and EXR; opt-in USD, FBX and Assimp
  • Scene serialization as three.js Object JSON or a single-file .tpz archive; three.js editor documents load as-is

Rendering beyond three.js

  • A deferred Vulkan renderer: raster G-buffer, ray-traced shadows, reflections, AO and probe GI, volumetric fog, denoising and TAA, DLSS and FSR 3.1 upscaling, automatic mesh LOD and GPU occlusion culling
  • Ocean (Vulkan): three-cascade FFT water with foam, wind, JONSWAP fetch and an underwater view
  • ParticleField (Vulkan): GPU particles for fire, smoke, snow, rain and physics-coupled grains, drawn as meshes or billboards, or marched as participating media
  • Gaussian splatting: SplatCloud renders .ply and SOG scans on both backends, and a scan can be baked into a triangle surface for physics and sensors (doc/vulkan_splats.md)

Simulation and perception

  • Ground-truth labels from the G-buffer (Vulkan): metric depth, stable instance ids, semantic classes, normals and motion; addView renders a whole camera rig from one scene build
  • Simulated sensors: lidar (VLP-16, HDL-32E, OS1-64, OS0-128 patterns), imaging sonar (Vulkan), depth, colour and event cameras, IMU, joint encoders, contact and force/torque. Seeded and sim-clock stamped: drive setSimTime from the same clock and a frame replays bit for bit
  • A physical camera: exposure from aperture, shutter and ISO, OpenCV intrinsics, lens distortion applied to both image and labels, and sensor noise
  • PhysX: rigid bodies, articulations built from URDF/xacro with PD drives, tendons and cables, soft bodies, GPU particles, vehicles, character controllers and V-HACD convex decomposition, plus a damped-least-squares IK solver
  • Soft and granular ground from Python on NVIDIA Warp: Bekker-Wong mud and snow, and MLS-MPM grains that carry a wheel, checked against terramechanics data
  • Hardware-in-the-loop: an unmodified ArduPilot flies a threepp airframe in lock-step (doc/ardupilot_sitl.md)
  • Zero-copy CUDA interop: an external producer such as NVIDIA Warp writes vertex buffers in place, and rendered frames come back as CUDA tensors

Content and tooling

  • Procedural terrain, trees, grass, roads, conveyors, bird flocks and a log cabin; real-world terrain built from Norwegian open data (terrain::GeoScene)
  • Audio via miniaudio, with ray-traced occlusion and reverb (AcousticScene)
  • Dear ImGui integration
  • Builds on Windows, Linux, macOS, MinGW and with Emscripten

Applications

The threepp scene editor

  • threepp_editor: viewport, hierarchy, inspector, undo/redo and a PhysX-backed Play mode, with Python behaviour scripts. Scenes save as plain three.js JSON with the editor's data in userData, so they also run in an ordinary threepp program. Prebuilt for Windows: pip install threepp-editor. See doc/editor.md.
  • threepp_player: the same play runtime, headless, for CI and batch episodes. See doc/player.md.

Both build alongside the library in a top-level build (THREEPP_BUILD_EDITOR).

Project status

threepp is built for research, prototyping and teaching, not as a production engine. APIs change, so pin a tag or commit if you need reproducibility.

The three.js port is the mature layer, and the one most users touch. The simulation layer on top (the Vulkan renderer, sensors, PhysX, the editor and Python) is where development goes, and it moves fastest. Limits worth knowing:

  • The Vulkan backend needs the Vulkan ray-tracing extensions (in practice an RT-capable GPU), so it does not run on macOS, where MoltenVK has none. Use GLRenderer there; it is also the conservative choice elsewhere.
  • Gaussian splats cast no shadows and are invisible to the ray-traced sensors unless baked into a surface.
  • The editor is tested on OpenGL; its Vulkan viewport is best-effort.
  • CI has no GPU. The Vulkan backend runs there on lavapipe under the validation layers, which gates spec correctness, not pixels.

Example

#include "threepp/threepp.hpp"

using namespace threepp;

int main() {

    Canvas canvas{"Demo"};
    GLRenderer renderer{canvas};

    auto scene = Scene::create();
    auto camera = PerspectiveCamera::create(75, canvas.aspect(), 0.1f, 100.f);
    camera->position.z = 5;

    OrbitControls controls{*camera, canvas};

    scene->add(HemisphereLight::create());

    auto material = MeshPhongMaterial::create();
    material->color = Color::green;
    auto box = Mesh::create(BoxGeometry::create(), material);
    scene->add(box);

    canvas.onWindowResize([&](WindowSize size) {
        camera->aspect = size.aspect();
        camera->updateProjectionMatrix();
        renderer.setSize(size);
    });

    Clock clock;
    canvas.animate([&] {
        box->rotation.y += 1.f * clock.getDelta();
        renderer.render(*scene, *camera);
    });
}

Swap GLRenderer for VulkanRenderer and the scene code stays the same. Math classes are value types; everything else is created through a static ::create that returns a std::shared_ptr, and GPU resources are released when the last reference goes. threepp/threepp.hpp covers the three.js core; extras/, postprocessing/, splats/ and the newer objects are included explicitly.

Python

pip install threepp

Wheels for CPython 3.10 to 3.14 on Windows x64 and manylinux x86_64 carry the OpenGL and Vulkan renderers and CPU PhysX. macOS builds from source (OpenGL only). Releases are named by date; pin the one you tested.

import threepp as tp

canvas = tp.Canvas("offscreen", width=800, height=600, headless=True)
renderer = tp.GLRenderer(canvas)

scene = tp.Scene()
camera = tp.PerspectiveCamera(75, 800 / 600, 0.1, 100)
camera.position.z = 5

mat = tp.MeshStandardMaterial()
mat.color = 0x00aaff
scene.add(tp.Mesh(tp.BoxGeometry(), mat))
scene.add(tp.HemisphereLight())

renderer.render(scene, camera)
pixels = renderer.read_pixels()   # (H, W, 3) uint8 NumPy array
renderer.save_frame("out.png")

The module also exposes the Vulkan labels as NumPy arrays, PhysX articulations, CUDA interop and threepp.rl, a GPU-vectorized PPO stack. A headless canvas needs no display, so the same code runs on Colab and cloud GPUs. python/README.md is the full guide, with the extras (threepp[rl], threepp[editor]) and the Python examples.

Building

All core dependencies are bundled. CMakePresets.json holds the configurations CI builds:

Preset What you get
gl OpenGL backend, with examples, tests and the editor (start here)
gl-debug as gl, unoptimised and with debug info
vulkan the deferred Vulkan renderer (Vulkan SDK on PATH, or the vcpkg vulkan feature)
vulkan-aaa as vulkan, plus the FSR 3.1 and DLSS upscalers (Windows)
python the pybind11 threepp module
no-glfw build check only: no GLFW frontend, so no rendering
wasm Emscripten/WebGL2 examples (needs an activated emsdk)
cmake --preset gl
cmake --build --preset gl
ctest --preset gl

Each preset builds into build/<preset>. cmake --list-presets also lists the ci-* presets the GitHub workflow runs, and machine-specific presets belong in an untracked CMakeUserPresets.json that inherits from these. Without presets, cmake -B build and cmake --build build work as usual; add -DTHREEPP_USE_EXTERNAL_GLFW=ON to use a system GLFW.

A subset of the examples runs in the browser: try them online.

Some headers need extra packages when you consume them:

Header Dependency Notes
AssimpLoader assimp Import a wide range of 3D formats
ImguiContext imgui Dear ImGui utility
Physx*, ConvexDecomposition physx, v-hacd Physics simulation and concave colliders
Vulkan*, Ocean, ParticleField, SonarSensor, and others Vulkan SDK Linked only under THREEPP_WITH_VULKAN, which the threepp target propagates

Using threepp in your project

CMake FetchContent is the recommended and tested route:

include(FetchContent)
FetchContent_Declare(
        threepp
        GIT_REPOSITORY https://github.com/markaren/threepp.git
        GIT_TAG tag_or_branch
        GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(threepp)
target_link_libraries(main PUBLIC threepp::threepp)

Consumed this way only the library builds, and the example assets in threepp_data are never downloaded. A complete setup is in tests/threepp_fetchcontent_test, and threepp_wxwidgets embeds threepp in a wxWidgets window. threepp is also on Conan Center, which xmake can consume too; see doc/package_managers.md for both and their caveats.

Why?

Because C++ deserves nice things too. Also, because fun.

It also turns out to suit AI-assisted development: a three.js API that models already know, few dependencies, first-party source all the way down to the Vulkan shaders, and a short loop from code to a rendered image that can be captured headless and judged.

Gallery

A drone light show writes threepp over the Stigfossen waterfall at Trollstigen
Vulkan and Warp: a drone light show writes the name at dusk over Stigfossen, in a digital twin of Trollstigen, Norway; the drones are a ParticleField and the waterfall is GPU parcels (the scene is not in the repository)
Sea kayak in a digital twin of a waterfront in Ålesund
Vulkan: a sea kayak under way in the same digital twin as the Otter X at the top of this page (the scene is not in the repository)
Rover on a sand slope
Vulkan and Warp: a rover climbs loose sand in GPU grains, with slip plotted against tilt-bed data (rover)
OpenGL showpiece
OpenGL: room lighting, glass, soft shadows, GTAO, bloom and outline in one frame (showpiece)
Spot RL gait, procedural forest
Vulkan: an RL-trained Spot walks a procedural forest while its depth camera builds a live SLAM surface (spot_slam.py)
OpenGL studio scene
OpenGL from Python: soft shadows, ambient occlusion and a selection outline (gl_studio.py)
GPU particle field
Vulkan: a campfire ParticleField, marched as participating media (vulkan_fire)
Franka FR3 with a depth camera
OpenGL: a depth camera on a Franka FR3, placed by IK, scans a tray (lesson part 2, depth_map.py)
Sphero RVR following a ball
OpenGL: a Sphero RVR follows a ball by what its own camera sees, driven through the real robot's two drive commands (SpheroControl)
SVG loader
OpenGL and Vulkan: the SVG loader (svg_loader)

License

threepp is MIT-licensed. It ports the API and shaders of three.js (MIT) and bundles or fetches a number of third-party libraries and assets; see THIRD_PARTY.md for the full index, including the parts that are not MIT (the optional NVIDIA DLSS SDK, and the Boston Dynamics Spot model in threepp_data).

About

A cross-platform C++20 3D library with Python bindings and the high-level API of three.js.

Topics

Resources

Stars

971 stars

Watchers

17 watching

Forks

Releases

Used by

Contributors

Languages