Parametric curve is always in front of Surface

Question:

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:

Dehn twist in Mathematica

I managed to parametrize the curve and surface correctly in Manim.

Dehn twist 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:
Torus with set_shade_in_3d()

As you can see part of the red path that should be in front of the torus is not being shaded correctly.

Asked By: Astyx

||

Answers:

set_shade_in_3d_true. this will calculate the depth of the curve with the torus…
i.e.

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
    ).set_shade_in_3d(true)

Then, if you want the curve to pop a little bit above the torus, add epsilon in the relevant direction to the curve coordinates

Answered By: A-_-S

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.

Answered By: Paritosh Kulkarni
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.