Description
Description of bug / unexpected behavior
A glowdot can be made by nesting a bunch of gradually more transparent balls. The OpenGL renderer depth tester doesn't behave well with this situation and renders it as a dimmer, dull, no longer glowing dot. (Problems with transparancy is apparently a known common OpenGL problem, not directly a Manim problem).
Expected behavior
A glowing dot that correctly moves in front of and behind other objects. If I have a static camera pose, then I can be more careful about the order I add objects, but if my camera pose is dynamic, this won't work.
How to reproduce the issue
Code for reproducing the problem
class Tester(ThreeDScene):
def construct(s):
sphere_1 = OpenGLSurface(lambda u, v: np.array([np.cos(u)*np.sin(v), np.sin(u)*np.sin(v), -np.cos(v)]), (0, TAU), (0, PI), color=BLUE_D)
glowdot = GlowDot(point = 2*RIGHT, radius=70, num_layers=20, color_fade=[YELLOW, YELLOW_E])
glowdot_bad = GlowDot(point = 4*RIGHT, radius=70, num_layers=20, color_fade=[YELLOW, YELLOW_E])
glowdot_bad.apply_depth_test()
s.add(glowdot, glowdot_bad, sphere_1)
# orbit animation
orbit_1 = Circle(radius=2).rotate(PI/2, RIGHT)
orbit_2 = Circle(radius=4).rotate(PI/2, RIGHT)
s.play(MoveAlongPath(glowdot, orbit_1, run_time=3), MoveAlongPath(glowdot_bad, orbit_2, run_time=6), rate_func=rate_functions.linear)
s.pause()
class GlowDot(OpenGLPGroup):
def __init__(
self,
point: np.ndarray = ORIGIN,
radius: float = 1,
num_layers: int = 80,
color_fade: ManimColor = [YELLOW, YELLOW_E],
**kwargs
) -> None:
self.point = point
self.radius = radius
self.num_layers = num_layers
self.color_fade = color_fade
super().__init__(**kwargs)
self.init_orbs()
def init_orbs(self):
color_list = color_gradient(self.color_fade, self.num_layers)
opacity_func = lambda t: 1500 * (1 - abs(t - 0.009) ** 0.0001)
rate_func = lambda t: t**2
for i in range(self.num_layers):
orb = OpenGLPMobject(
stroke_width=self.radius*rate_func((0.5 + i)/self.num_layers),
color=color_list[i],
opacity=opacity_func(rate_func(i/self.num_layers))
)
orb.add_points(self.point)
self.add(orb)
Patch Solution I Made
The issue seems to be with the OpenGL depth tester in regards to transparent objects. My bad idea patch solution is in my scene construct to set depth testing for all opaque objects but disable depth testing for transparent objects. Then I modified the update_frame
method of class OpenGLRenderer
to sort the mobjects in order of farthest to nearest to the camera. This performs expected behavior almost always. Why do depth testing for opaque objects then? For some reason some objects look better with it on (e.g. textured surfaces).
code for my bad idea patch
def update_frame(self, scene):
self.frame_buffer_object.clear(*self.background_color)
self.refresh_perspective_uniforms(scene.camera)
### MY CODE FIXME ###
def z_key(mob):
# Assign a number to a three dimensional mobjects
# based on how close it is to the camera
return np.linalg.norm(self.camera.get_position() - mob.get_center())
scene.mobjects = sorted(scene.mobjects, key=z_key, reverse=True)
##############
for mobject in scene.mobjects:
if not mobject.should_render:
continue
self.render_mobject(mobject)
for obj in scene.meshes:
for mesh in obj.get_meshes():
mesh.set_uniforms(self)
mesh.render()
self.animation_elapsed_time = time.time() - self.animation_start_time
Additional media files
Images/GIFs
Both glowdots orbit the planet. The outer glowdot is depth tested. It doesn't glow, has weird border issues, and even blocks the planet. The inner glowdot glows, but due to the order added, only shows behind the planet.Logs
Terminal output
The debug output contains the following repeated many times:DEBUG \surface\geom.glsl does not exist. shader_wrapper.py:35
DEBUG C:\Users\colin\AppData\Local\Programs\Pyt shader_wrapper.py:35
hon\Python312\Lib\site-packages\manim\ren
derer\shaders\surface\geom.glsl does not
exist.
System specifications
System Details
- OS: Windows 10 Home v2022
- RAM: 8GB
- Python version: 3.12.9
- Installed modules:
Package Version
----------------------- -----------
aiohappyeyeballs 2.4.6
aiohttp 3.11.12
aiortsp 1.4.0
aiosignal 1.3.2
annotated-types 0.7.0
asttokens 3.0.0
attrs 25.1.0
av 13.1.0
beaupy 3.10.1
beautifulsoup4 4.13.3
Brotli 1.1.0
click 8.1.8
cloup 3.0.5
colorama 0.4.6
contourpy 1.3.1
cycler 0.12.1
decorator 5.1.1
dpkt 1.9.8
emoji 2.14.1
executing 2.2.0
fonttools 4.56.0
frozenlist 1.5.0
glcontext 3.0.0
idna 3.10
ifaddr 0.2.0
ipython 8.32.0
isosurfaces 0.1.2
jedi 0.19.2
kiwisolver 1.4.8
manim 0.19.0
ManimPango 0.6.0
mapbox_earcut 1.0.3
markdown-it-py 3.0.0
matplotlib 3.10.0
matplotlib-inline 0.1.7
mdurl 0.1.2
moderngl 5.12.0
moderngl-window 3.1.1
multidict 6.1.0
networkx 3.4.2
numpy 2.2.2
packaging 24.2
pandas 2.2.3
parso 0.8.4
pillow 11.1.0
pip 25.0.1
pl-neon-recording 0.1.12
prompt_toolkit 3.0.50
propcache 0.2.1
protobuf 5.29.3
pupil_labs_realtime_api 1.3.6
pure_eval 0.2.3
pycairo 1.27.0
pydantic 2.10.6
pydantic_core 2.27.2
pydub 0.25.1
pyglet 2.1.2
pyglm 2.8.0
Pygments 2.19.1
PyOpenGL 3.1.9
pyparsing 3.2.1
PyQt5 5.15.11
PyQt5-Qt5 5.15.2
PyQt5_sip 12.17.0
pyqtgraph 0.13.7
pyserial 3.5
python-dateutil 2.9.0.post0
python-yakh 0.4.1
pytz 2025.1
questo 0.4.1
rich 13.9.4
scipy 1.15.1
screeninfo 0.8.1
six 1.17.0
skia-pathops 0.8.0.post2
soupsieve 2.6
srt 3.5.3
stack-data 0.6.3
structlog 25.1.0
svgelements 1.9.6
tqdm 4.67.1
traitlets 5.14.3
typing_extensions 4.12.2
tzdata 2025.1
watchdog 6.0.0
wcwidth 0.2.13
websockets 14.2
yarl 1.18.3
zeroconf 0.144.1
Metadata
Metadata
Assignees
Labels
Type
Projects
Status