Skip to content

3D models and data

Use 3D when depth is the idea: a surface, vectors in space, a real object turned to show another side, or an object cut open to show its inside. Keep the rest of the video flat; it reads faster.

A 3D camera: Episode3D

Subclass Episode3D instead of Episode. self.move_camera(phi=..., theta=...) tilts and turns the camera while a line is spoken, begin_ambient_camera_rotation() orbits slowly, and self.pin(...) keeps a label flat on screen. The header and progress bar stay flat, and title, chapter and recap cards are never tilted. For a surface z = f(x, y), add the surface-plot block.

Models from files

A model file goes in two ways. From Blender, export glTF 2.0 (.glb): it keeps the colours, the part names and the animations.

mesh-model block from_model clip
Drawn by Manim, one shaded face per triangle a 3D renderer, with real lighting and materials
Camera Manim's: tilt, orbit, labels pinned beside it its own orbit, set when the clip is made
Detail simplified to at most 5000 faces every triangle
Parts mesh_part picks faces to recolour or label none: the clip is one picture
glTF animations no yes, played in step with the clip
Extra trimesh pyvista
from blocks.mesh_model import mesh_model, mesh_part      # after `manimvox add mesh-model`
part = mesh_model("research/engine.glb", size=5)
valves = mesh_part(part, name="valve")                    # a glTF part by name

from manimvox.scenes import from_model
clip = from_model("research/engine.glb", seconds=6, orbit=360).loop()   # keeps turning under the narration

Scans, simulations and cut-open views: from_pyvista

from_pyvista(draw, seconds, setup=...) renders any PyVista scene as a clip: setup(plotter) once, then draw(plotter, t) before each frame. Each frame is drawn from its own time, so a draft and a final render match. Inside draw, screen_xy(plotter, point) gives a 3D point's pixel, and clip.at(x, y) turns that pixel into a scene point for a label or a path.

To show an inside, cut a volume mesh (from a scan or a simulation) with mesh.clip(normal=..., origin=...), and move origin over time to slice it open on screen. A model downloaded as a surface is hollow when cut. Inside the heart does exactly this with a CT-derived heart.

Where it runs

from_model and from_pyvista need OpenGL 3.2: a graphics driver on a desktop, sudo apt install libegl1 libosmesa6 on a Linux server with no display, or Mesa's software opengl32.dll on a Windows server. Without it, they stop with a message naming the fix. CI runs these tests on all three systems.

Licences

A model or scan from the web has a licence: check that it allows your use, put its credit on screen, and record it in FACTS.md.