ManimCommunity / manim

A community-maintained Python framework for creating mathematical animations.
https://www.manim.community
MIT License
20.96k stars 1.52k forks source link

Fixed-in-frame mobject is not transforming correctly in 3D scene #3252

Open MqCreaple opened 1 year ago

MqCreaple commented 1 year ago

Here is the code:

class Test(ThreeDScene):
    def construct(self):
        axes = ThreeDAxes()
        self.set_camera_orientation(phi = 75 * DEGREES, theta = 45 * DEGREES)
        self.play(Create(axes))
        eq1 = MathTex(r'x')
        eq1.to_corner(UL)
        self.add_fixed_in_frame_mobjects(eq1)
        self.play(Create(eq1))
        eq2 = MathTex(r'x^2')
        eq2.to_corner(UL)
        self.play(Transform(eq1, eq2))

In my computer, the animation it produced does not transformed formula $x$ into $x^2$. It only shifts the text $x$ downward but does not write the superscript $2$.

https://github.com/ManimCommunity/manim/assets/86477788/df7603bf-d594-404e-9a14-6e6a14bd02a0

JinchuLi2002 commented 1 year ago

Essentially two issues here:

  1. superscript not showing up
  2. fixed-in-frame Mobjects seemed buggy during and after transformation (see on the right of your video)

Haven't figured out the root causes yet, but I was able to workaround (1) by setting the renderer as OpenGL and (2) by inserting the below two lines after the Transformation from eq1 to eq2

self.remove(eq1)
self.add_fixed_in_frame_mobjects(eq2)
MqCreaple commented 1 year ago

It seems that the superscript 2 is written on the xy plane, if you look carefully around the right edge of the screen. In other word, it is not 'fixed in frame'. I don't know the cause of it though. I haven't read manim's source code yet.

uwezi commented 1 year ago

Manim always creates new 2D objects by default in the xy-plane. And a Transform does not move an object around. Only eq1 in the example is fixed in the frame and does follow the movement of the camera. Manim currently lacks an in-frame placement of objects, even though it should be not to complicated to create such a function.

However, for the example here I would probably suggest something like this:

class Test(ThreeDScene):
    def construct(self):
        axes = ThreeDAxes()
        eq1 = MathTex(r'x')
        eq1.to_corner(UL)
        eq2 = MathTex(r'x^2')
        eq2.move_to(eq1.get_corner(DL), aligned_edge=DL)

        self.add_fixed_in_frame_mobjects(eq1,eq2)
        eq1.set_opacity(0)
        eq2.set_opacity(0)

        self.set_camera_orientation(phi = 75 * DEGREES, theta = 45 * DEGREES)
        self.play(Create(axes))

        self.play(eq1.animate.set_opacity(1))
        self.wait()
        self.play(
            eq1.animate.set_opacity(0),
            eq2.animate.set_opacity(1),
        )    
        self.wait()    

https://github.com/ManimCommunity/manim/assets/8582807/2a627c42-641d-4845-b0c6-a82c2f1821f9

uwezi commented 1 year ago

Moving the objects into the camera frame works, but using .add_fixed_in_frame_objects() does not...

class Test(ThreeDScene):
    def construct(self):
        axes = ThreeDAxes()
        eq1 = MathTex(r'x')
        eq1.to_corner(UL)
        eq2 = MathTex(r'x^2')
        eq2.move_to(eq1.get_corner(DL), aligned_edge=DL).shift(DOWN)

        self.set_camera_orientation(phi = 75 * DEGREES, theta = 45 * DEGREES)
        self.play(Create(axes))

        eq1.apply_matrix(np.linalg.inv(self.camera.generate_rotation_matrix()))
        eq2.apply_matrix(np.linalg.inv(self.camera.generate_rotation_matrix()))

        self.play(Write(eq1))
        self.wait()
        #self.add_fixed_in_frame_mobjects(eq1,eq2) # <- does not work! 
        self.play(ReplacementTransform(eq1, eq2))   
        self.wait()   
        self.move_camera(theta=((180+45) * DEGREES))        
        self.wait()