ManimCommunity / ManimCommunity/manim

Cairo does not respect order of mobjects when rendering a 3d scene

Open
#4,336 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
40.9k
Forks
3.1k
Avg merge
3d 12h
Merged PRs (30d)
25

Description

## Description of bug / unexpected behavior

I created a 3d scene that contained some Square and Line3D mobjects.
I sorted the mobjects into the correct z-order, but the Cairo renderer always seemed to draw the Square on top of the Line3D mobjects. I then switched to using the OpenGL renderer it produced the correct result.

Is this a known limitation of the Cairo renderer? I will workaround this issue by using the OpenGL rendered for 3d scenes.
However, I thought it was worth reporting this issue.

## Expected behavior

I expected the Cairo rendered to drawn the mobjects in the order that I added them to the scene.
Instead, it seems to always draw the Square on top of the Line3D mobjects.
The OpenGL rendered produced the expected result.

## How to reproduce the issue

Run the code twice. Once with OPENGL_CONFIG and again with CAIRO_CONFIG.
Note the different results.

Code for reproducing the problem

```py
"""
This module illustrates drawing lines over a square in a 3D scene using Manim.
"""
import numpy as np
from manim import (ThreeDScene, ThreeDAxes, Line3D, Square, config, tempconfig, RendererType,
LEFT, RIGHT, UP, OUT, WHITE, RED, BLUE, Text, UL)

class Line3DExample(ThreeDScene):
def construct(self):

renderer_str = f"renderer: {config.renderer.value}"
renderer_text = Text(renderer_str)
self.add_fixed_in_frame_mobjects(renderer_text)
renderer_text.to_corner(UL)

axes = ThreeDAxes()
x_label = axes.get_x_axis_label('x')
y_label = axes.get_y_axis_label('y')
z_label = axes.get_z_axis_label('z')
self.add(axes, x_label, y_label, z_label)

# the square is in the plane z = 0
square = Square(side_length=3.0, color=RED, fill_opacity=1.0, stroke_color=BLUE, stroke_width=10)

# the 5 lines are in the planes z = -2, -1, 0, 1, 2
lines = [Line3D(2.0 * LEFT + t * (UP + OUT), 2.0 * RIGHT + t * (UP + OUT), color=WHITE)
for t in np.linspace(-2.0, 2.0, 5)]

# square and lines are added in the correct order
self.add(lines[0], lines[1], lines[2], square, lines[3], lines[4])

# opengl renders the scene correctly
# lines[3] is drawn over the square
OPENGL_CONFIG = {
"renderer": RendererType.OPENGL
}

# cairo renders the scene incorrectly
# lines[3] is drawn under the square
# this is a bug in cairo renderer
CAIRO_CONFIG = {
"renderer": RendererType.CAIRO
}

# For running the scene directly
if __name__ == "__main__":
with tempconfig(OPENGL_CONFIG):
scene = Line3DExample()
scene.render(preview=True)
```

## Additional media files

Images/GIFs

Image
Image

## Logs
Terminal output

```
PASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR
```

## System specifications

System Details

- OS: macOS 15.5 (24F74) (Sequoia)
- RAM: Mac Studio 2023 Apple M2 Max 96 GB
- Python version: Python 3.13.5
- Installed modules (provide output from `pip list`):
```
Package Version
------------------------- --------------
anyio 4.9.0
appnope 0.1.4
argon2-cffi 25.1.0
argon2-cffi-bindings 21.2.0
arrow 1.3.0
asttokens 3.0.0
async-lru 2.0.5
attrs 25.3.0
audioop-lts 0.2.1
av 13.1.0
babel 2.17.0
beautifulsoup4 4.13.4
bleach 6.2.0
certifi 2025.7.14
cffi 1.17.1
charset-normalizer 3.4.2
click 8.2.1
cloup 3.0.7
comm 0.2.2
Cython 3.1.2
debugpy 1.8.14
decorator 5.2.1
defusedxml 0.7.1
executing 2.2.0
fastjsonschema 2.21.1
fqdn 1.5.1
glcontext 3.0.0
h11 0.16.0
httpcore 1.0.9
httpx 0.28.1
idna 3.10
ipykernel 6.29.5
ipython 9.4.0
ipython_pygments_lexers 1.1.1
isoduration 20.11.0
isosurfaces 0.1.2
jedi 0.19.2
Jinja2 3.1.6
json5 0.12.0
jsonpointer 3.0.0
jsonschema 4.24.0
jsonschema-specifications 2025.4.1
jupyter_client 8.6.3
jupyter_core 5.8.1
jupyter-events 0.12.0
jupyter-lsp 2.2.5
jupyter_server 2.16.0
jupyter_server_terminals 0.5.3
jupyterlab 4.4.4
jupyterlab_pygments 0.3.0
jupyterlab_server 2.27.3
manim 0.19.0
ManimPango 0.6.0
mapbox_earcut 1.0.3
markdown-it-py 3.0.0
MarkupSafe 3.0.2
matplotlib-inline 0.1.7
mdurl 0.1.2
mistune 3.1.3
moderngl 5.12.0
moderngl-window 3.1.1
nbclient 0.10.2
nbconvert 7.16.6
nbformat 5.10.4
nest-asyncio 1.6.0
networkx 3.5
notebook_shim 0.2.4
numpy 2.3.1
overrides 7.7.0
packaging 25.0
pandocfilters 1.5.1
parso 0.8.4
pexpect 4.9.0
pillow 11.3.0
pip 25.1.1
platformdirs 4.3.8
prometheus_client 0.22.1
prompt_toolkit 3.0.51
psutil 7.0.0
ptyprocess 0.7.0
pure_eval 0.2.3
pycairo 1.28.0
pycparser 2.22
pydub 0.25.1
pyglet 2.1.6
pyglm 2.8.2
Pygments 2.19.2
pyobjc-core 11.1
pyobjc-framework-Cocoa 11.1
python-dateutil 2.9.0.post0
python-json-logger 3.3.0
PyYAML 6.0.2
pyzmq 27.0.0
referencing 0.36.2
requests 2.32.4
rfc3339-validator 0.1.4
rfc3986-validator 0.1.1
rich 14.0.0
rpds-py 0.26.0
scipy 1.16.0
screeninfo 0.8.1
Send2Trash 1.8.3
setuptools 80.9.0
six 1.17.0
skia-pathops 0.8.0.post2
sniffio 1.3.1
soupsieve 2.7
srt 3.5.3
stack-data 0.6.3
svgelements 1.9.6
terminado 0.18.1
tinycss2 1.4.0
tornado 6.5.1
tqdm 4.67.1
traitlets 5.14.3
types-python-dateutil 2.9.0.20250708
typing_extensions 4.14.1
uri-template 1.3.0
urllib3 2.5.0
watchdog 6.0.0
wcwidth 0.2.13
webcolors 24.11.1
webencodings 0.5.1
websocket-client 1.8.0
```

LaTeX details

+ LaTeX distribution: TeXShop 5.53
+ Installed LaTeX packages:

too long, not relevant

## Additional comments

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the provided Line3DExample reproduction and run it with OPENGL_CONFIG and CAIRO_CONFIG to compare the render order. Trace the Cairo renderer's handling of ThreeDScene mobjects, especially Square and Line3D objects, and determine why insertion order differs. Done means Cairo renders the objects in the same expected z-order as OpenGL, with a regression test covering the example.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.