I am trying to build an animation of a Dehn twist in a torus in Manim. My goal is to get something that looks like this:
I managed to parametrize the curve and surface correctly in Manim.
As you can see, the portion of the parametric curves that should be hidden are entirely visible, which makes the picture harder to understand. How can I make the visualization show whether the curve is in front of or behind the surface?
I have looked at the Manim community documentation but could not find anything on this topic.
Here is code reproducing the image above:
from manim import *
class DehnTwist(ThreeDScene):
def torus_coordinates(self, u, v, t=0):
return np.array([np.cos(u), np.sin(u), 0]) + 1/2 * (t * abs(np.sin(u/2)) + 1 - t) * np.array([np.cos(u)* np.cos(v), np.sin(u)*np.cos(v), np.sin(v)])
def cycle_a_twisted_coordinates(self, u, t=0):
return np.array([np.cos(u), -np.sin(u),0]) + 1/2*(t*abs(np.sin(u/2))+1-t)*np.array([np.sin(u)*np.cos(u),-np.sin(u)*np.sin(u), np.cos(u)])
def cycle_a_twisted(self, t, axes):
return ParametricFunction(
lambda u: axes.c2p(*self.cycle_a_twisted_coordinates(u,t)),
t_range=[0,TAU],
color=PURE_RED
)
def torus(self, t, axes):
return Surface(
lambda u, v: axes.c2p(*self.torus_coordinates(u, v, t)),
u_range=[0, TAU],
v_range=[0, TAU],
fill_opacity=0.6,
resolution=20,
)
def construct(self):
axes = ThreeDAxes(x_range=[-4,4], x_length=8)
torus = self.torus(0, axes)
cycle_a_twisted = self.cycle_a_twisted(0, axes)
self.set_camera_orientation(theta=-30 * DEGREES, phi=60 * DEGREES)
self.camera.set_zoom(2)
self.add(cycle_a_twisted,torus)
EDIT: I have updated my code with regards to @A-_-S 's answer, and also simplified the curve for lisibility.
from manim import *
class DehnTwist(ThreeDScene):
def torus_coordinates(self, u, v):
return np.array([np.cos(u), np.sin(u), 0]) + 1/2 * np.array([np.cos(u)* np.cos(v), np.sin(u)*np.cos(v), np.sin(v)])
def cycle_a_twisted_coordinates(self, u):
return np.array([1, 0,0]) + (1/2+1/10)*np.array([-np.cos(u), 0, np.sin(u)])
def cycle_a_twisted(self, axes):
return ParametricFunction(
lambda u: axes.c2p(*self.cycle_a_twisted_coordinates(u)),
t_range=[0,TAU],
color=PURE_RED
).set_shade_in_3d(True)
def torus(self, axes):
return Surface(
lambda u, v: axes.c2p(*self.torus_coordinates(u, v)),
u_range=[0, TAU],
v_range=[0, TAU],
fill_opacity=1,
resolution=20,
)
def construct(self):
axes = ThreeDAxes(x_range=[-4,4], x_length=8)
torus = self.torus(axes)
cycle_a_twisted = self.cycle_a_twisted(axes)
self.set_camera_orientation(theta=-30 * DEGREES, phi=60 * DEGREES)
self.camera.set_zoom(2)
self.add(cycle_a_twisted,torus)
This yields the following image:
As you can see part of the red path that should be in front of the torus is not being shaded correctly.
Maybe this will help - https://github.com/3b1b/manim/issues/1094
It seems like you may need two 2D wrapper curves one that is on the surface and the other that is behind, and increasing the granularity of the 2D behind the curve so that it will not pop up! I also did some digging and moving around the curve (2D), and the torus (3D but can be converted to 2D) will also resolve the issue, for which you need to save the torus into a 2D object and then use that (basically an image) to construct a single wrapper and shift it BEHIND https://docs.manim.community/en/stable/tutorials/building_blocks.html#mobject-on-screen-order
Best of luck! Sorry, I tried but was not able to submit a working code in a short time.