티스토리 뷰

https://www.youtube.com/watch?v=KHGoFDB-raE

출처는 다음 영상입니다. 해당 포스팅은 파이썬에대한 기초적인 선행지식은 있다고 가정합니다.

 

[3B1B 따라잡기 list]

2023.05.11 - [Computer/코딩 개꿀팁] - [3B1B 따라잡기 with Manim] 1. Manim 설치 with vscode

2023.05.12 - [Computer/코딩 개꿀팁] - [3B1B 따라잡기 with Manim] 2. How to create Scene

2023.05.15 - [Computer/코딩 개꿀팁] - [3B1B 따라잡기 with Manim] 3. Error message 파악하기

 

이번 포스팅에서는 play한 Mobject를 animation기능을 사용해서 update하는 방법을 공부해본다. 상당히 중요하고 manim library를 사용하는 가장 큰 이유라고도 볼 수 있으니 잘 따라오길 바란다! 나도 공부하며 정리하는 포스팅이라 해당 시리즈에서는 고도화된 수준의 애니메이션은 없겠지만 추후 심화 포스팅에서 더 다룰 예정이니 지금은 기초적인 수준의 애니메이션 업데이트를 해보는데 의미를 두자

먼저 다음과 같이 코드를 작성해보자

class Getters(Scene): # Scene을 위한 class 선언
    def construct(self): # def construct(self)는 __init__같은 느낌 정형화된 표현이니 외우자

        rect = Rectangle(color=WHITE, height=3, width=2.5).to_edge(UL)
        # 하얀색의 높이가 3 너비가 2.5인 Rectangle Mobject저장, 가장자리 UpperLeft(UL)로 이동

        circ = Circle().to_edge(DOWN)
		# 기본형태의 원을 가장자리 DOWN으로 이동
        
        arrow = Line(start = rect.get_bottom(), end = circ.get_top(), buff=0.45).add_tip()
		# 화살표, 시작은 rect에서 .get_bottom()을 이용해 rect의 바닥지점에서 시작
        # end는 circ에서 .get_top()을 이용해 circ의 top에서 끝
        # buff는 화살표가 0.45만큼 도형들로부터 거리를 두는(margin을 주는)역할
        # .add_tip()을 이용해 꼬다리에 화살표 표현
        
        self.play(Create(VGroup(rect, circ, arrow)), run_time=4)
        # VGroup은 여러가지 Mobject를 하나로 묶어 scaling이나 move를 할때 함께 움직이도록 함
        # VGropu에 대한 포스팅은 추가로 할 예정
        self.wait()
        self.play(rect.animate.to_edge(UR))
        # rect Mobject를 .animate를 이용해서 update

특히, 맨 마지막줄의 update에 주의해보자, 한가지 의문점 과연 arrow는 rect를 따라 움직일까? 

안타깝게도 화살표가 따라 움직이지 않는다. 그러면 다음처럼 화살표가 상자를 따라 움직이게 하려면 어떻게 해야될까?

코드를 다음과 같이 수정하자

class Getters(Scene):
    def construct(self):

        rect = Rectangle(color=WHITE, height=3, width=2.5).to_edge(UL)

        circ = Circle().to_edge(DOWN)
		
        # 기존 코드 #
        # arrow = Line(start = rect.get_bottom(), end = circ.get_top(), buff=0.45).add_tip()
        
        # 수정된 코드 #
        arrow = always_redraw(
            lambda : Line(start = rect.get_bottom(), end = circ.get_top(), buff=0.45).add_tip()
            )
        
        self.play(Create(VGroup(rect, circ, arrow)), run_time=4)
        self.wait(duration=2)
        self.play(rect.animate.to_edge(UR))
        self.wait(duration=2)

arrow 변수에 always_redraw()를 맨 앞에 추가했고, Line 변수를 lambda 변수로 지정해서 always_redraw의 객체가 될 변수로 Line을 지정해주었다. 그럼 이번에는 circ Mobject 객체를 shrink down해서 scale down하는 것 까지 update해보자.

원의 크기가 줄어드는 것을 확인할 수 있다. 코드는 다음과 같이 수정하면 된다.

class Getters(Scene):
    def construct(self):

        rect = Rectangle(color=WHITE, height=3, width=2.5).to_edge(UL)

        circ = Circle().to_edge(DOWN)

        # arrow = Line(start = rect.get_bottom(), end = circ.get_top(), buff=0.45).add_tip()
        arrow = always_redraw(
            lambda : Line(
            start = rect.get_bottom(), end = circ.get_top(), buff=0.45)
            .add_tip())
        self.play(Create(VGroup(rect, circ, arrow)), run_time=4)
        self.wait(duration=2)
        
        # 기존 코드 #
        # self.play(rect.animate.to_edge(UR))
        
        # 수정된 코드 #
        self.play(rect.animate.to_edge(UR), circ.animate.scale(0.5))
        self.wait(duration=2)

 

응용해보자 이런 애니메이션을 만들고 싶으면 어떻게 작성해야 할까?

어떤 그림을 어떻게 구성할지 머리속에서 잘 생각해야한다.

  1. 테두리가 그려지는 네모박스를 그려서, 테두리는 하얀색, 내부는 초록색으로 칠해야한다. (SurroundingRectangle을 이용한다.)
  2. 그 안에 log(2)라는 숫자를 적어야한다. log(2)의 위치는 박스의 정 중앙에 있다. (숫자형 텍스트는 MathTex를 이용한다.)
  3. 박스의 바로 아래에는 BDS Lab이라는 글자가 적힌다. (문자열 텍스트는 Tex를 이용한다.)
  4. 모든 도형과 글자가 하나처럼 움직이며 오른쪽으로 shift된다. (VGroup을 이용한다 + 함께 움직일 객체들을 always_redraw함수를 이용해서 다같이 움직이게 만들어준다.)

일단 이정도로 생각하면 얼추 유사한 도형을 만들 수 있을 것이다. 직접 한번 만들어보길 바란다.

더보기
class Updaters(Scene):
    def construct(self):

        num = MathTex("log(2)")
        box = always_redraw(lambda : 
                            SurroundingRectangle(num, color=WHITE, fill_opacity=0.2, 
                                                 fill_color=GREEN, buff=1.5))
        name= always_redraw(lambda : Tex("BDS Lab").next_to(box, DOWN, buff=0.25))
        
        self.play(Create(VGroup(num, box, name)))
        self.play(num.animate.shift(RIGHT * 2.5), run_time=2)
        self.wait(duration=2)
댓글