3D in ManimGL
ManimGL has powerful 3D capabilities with a flexible camera system. Unlike ManimCE, ManimGL doesn't require a special ThreeDScene class.
Basic 3D Setup
Creating 3D Objects
from manimlib import *
class Basic3DScene(Scene):
def construct(self):
# Get camera frame
frame = self.camera.frame
# Set 3D orientation
frame.reorient(20, 70) # theta, phi in degrees
# Create 3D objects
sphere = Sphere(radius=2)
sphere.set_color(BLUE, opacity=0.7)
self.add(sphere)Camera Frame Control
frame.reorient()
The reorient() method is the primary way to control 3D camera orientation.
# frame.reorient(theta, phi, gamma=0, center=ORIGIN, height=8)
# Front view
frame.reorient(0, 0)
# Isometric view
frame.reorient(20, 70)
# Top-down view
frame.reorient(0, 90)
# Side view
frame.reorient(90, 90)Animating Camera Movement
class AnimatedCamera(Scene):
def construct(self):
frame = self.camera.frame
# Create object
cube = Cube()
self.add(cube)
# Animate camera rotation
self.play(frame.animate.reorient(30, 60))
self.wait()
# Continuous rotation
frame.add_updater(lambda m, dt: m.increment_theta(0.2 * dt))
self.wait(10)Frame Methods
# Set Euler angles
frame.set_euler_angles(theta=30*DEGREES, phi=70*DEGREES)
# Increment angles (useful for rotation)
frame.increment_theta(10*DEGREES)
frame.increment_phi(5*DEGREES)
frame.increment_gamma(2*DEGREES)
# Get current angles
theta = frame.get_theta()
phi = frame.get_phi()3D Geometric Primitives
Sphere
sphere = Sphere(
radius=2,
resolution=(20, 20), # (u_resolution, v_resolution)
color=BLUE
)
sphere.set_opacity(0.7)Cube
cube = Cube(
side_length=2,
color=GREEN,
fill_opacity=0.8
)Surface
# Parametric surface
surface = Surface(
lambda u, v: np.array([u, v, u**2 + v**2]),
u_range=(-2, 2),
v_range=(-2, 2),
resolution=(20, 20)
)Torus
torus = Torus(
r1=2, # Major radius
r2=0.5, # Minor radius
color=YELLOW
)Cylinder
cylinder = Cylinder(
height=3,
radius=1,
color=RED
)3D Lines and Shapes
# 3D Line
line = Line3D(
start=[-2, -2, -2],
end=[2, 2, 2],
color=WHITE,
width=0.05
)
# 3D Disk
disk = Disk3D(radius=1.5, color=PURPLE)
# 3D Square
square = Square3D(side_length=2, color=ORANGE)Textured Surfaces
Adding Textures to 3D Objects
class TexturedSphere(Scene):
def construct(self):
frame = self.camera.frame
frame.reorient(20, 70)
# Create sphere with texture
sphere = Sphere(radius=2)
# Apply texture from URL or local file
textured_sphere = TexturedSurface(
surface=sphere,
# Can use URL or local path
image_file="path/to/texture.jpg"
)
self.add(textured_sphere)
# Rotate camera
self.play(frame.animate.increment_theta(360*DEGREES), run_time=10)Earth Example
earth = Sphere(radius=2, resolution=(40, 40))
textured_earth = TexturedSurface(
earth,
"https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Whole_world_-_land_and_oceans.jpg/1280px-Whole_world_-_land_and_oceans.jpg"
)3D Axes
ThreeDAxes
axes = ThreeDAxes(
x_range=(-5, 5, 1),
y_range=(-5, 5, 1),
z_range=(-5, 5, 1),
width=10,
height=10,
depth=10
)
axes.add_coordinate_labels(font_size=20)NumberPlane in 3D
# XY plane
xy_plane = NumberPlane(
x_range=(-5, 5),
y_range=(-5, 5)
)
# XZ plane (horizontal floor)
xz_plane = NumberPlane(
x_range=(-5, 5),
y_range=(-5, 5)
)
xz_plane.rotate(90*DEGREES, axis=RIGHT)Parametric Surfaces
Creating Custom Surfaces
# Paraboloid
paraboloid = Surface(
lambda u, v: np.array([
u,
v,
u**2 + v**2
]),
u_range=(-2, 2),
v_range=(-2, 2),
resolution=(30, 30),
color=BLUE
)
# Wave surface
wave = Surface(
lambda u, v: np.array([
u,
v,
np.sin(u) * np.cos(v)
]),
u_range=(-PI, PI),
v_range=(-PI, PI),
resolution=(40, 40)
)Surface Mesh
# Create surface
surface = Sphere(radius=2)
# Add mesh overlay
mesh = SurfaceMesh(surface)
mesh.set_stroke(BLUE, width=1, opacity=0.5)
self.add(surface, mesh)Fixing Objects in Frame
fix_in_frame()
Keep 2D elements (like labels) fixed while camera rotates.
class FixedLabels(Scene):
def construct(self):
frame = self.camera.frame
frame.reorient(20, 70)
# 3D object that rotates with camera
cube = Cube()
self.add(cube)
# 2D title that stays fixed
title = Text("3D Cube", font_size=60)
title.to_edge(UP)
title.fix_in_frame() # Stays in screen space
self.add(title)
# Rotate camera
self.play(frame.animate.reorient(50, 80), run_time=3)Lighting
Light Source
# Access light source
light = self.camera.light_source
# Move light
light.move_to([10, 10, 10])
# Animate light movement
self.play(light.animate.move_to([0, 0, 10]), run_time=2)Gloss and Shadow
# Add gloss to objects
sphere = Sphere(radius=2)
sphere.set_gloss(0.8) # 0 to 1
# Add shadow
sphere.set_shadow(0.5) # 0 to 1Complex 3D Scene Example
class Complex3DScene(Scene):
def construct(self):
frame = self.camera.frame
frame.reorient(20, 75)
# Create axes
axes = ThreeDAxes(
x_range=(-3, 3),
y_range=(-3, 3),
z_range=(-3, 3)
)
# Create parametric surface
surface = Surface(
lambda u, v: np.array([
u,
v,
np.sin(np.sqrt(u**2 + v**2))
]),
u_range=(-3, 3),
v_range=(-3, 3),
resolution=(30, 30),
color=BLUE
)
surface.set_opacity(0.7)
# Add mesh
mesh = SurfaceMesh(surface)
mesh.set_stroke(WHITE, 0.5, opacity=0.3)
# Add title (fixed in frame)
title = Text("Sinc Function Surface", font_size=48)
title.to_edge(UP)
title.fix_in_frame()
title.set_backstroke(BLACK, 5)
# Build scene
self.add(axes, surface, mesh, title)
self.wait()
# Rotate camera smoothly
self.play(
frame.animate.reorient(45, 70),
run_time=3
)
self.wait()
# Add continuous rotation
frame.add_updater(lambda m, dt: m.increment_theta(20 * dt))
self.wait(10)Interactive 3D Controls
When running with manimgl, you can interact with 3D scenes:
- Press
d+ move mouse: Rotate camera - Press
z+ scroll: Zoom in/out - Press
r: Reset camera to default position - Press
q: Exit interaction mode
Best Practices
- Use reorient(): Cleaner than setting Euler angles manually
- fix_in_frame() for labels: Keep UI elements readable
- Appropriate resolution: Higher resolution for final renders, lower for development
- Opacity for depth: Set opacity < 1 to see through surfaces
- Lighting matters: Adjust light source position for better visualization
- Continuous rotation: Use updaters for smooth camera rotation
- Frame rate considerations: 3D scenes may need lower frame rates during development
Common Patterns
Rotating camera around object
# 360-degree rotation
self.play(
frame.animate.increment_theta(360*DEGREES),
run_time=10,
rate_func=linear
)Creating a floor plane
floor = NumberPlane(
x_range=(-10, 10),
y_range=(-10, 10),
background_line_style={"stroke_color": GREY, "stroke_width": 1}
)
floor.rotate(90*DEGREES, RIGHT)
floor.shift(2*DOWN)Multiple viewpoints
# Show from different angles
angles = [(0, 0), (20, 70), (45, 45), (90, 90)]
for theta, phi in angles:
self.play(frame.animate.reorient(theta, phi))
self.wait()