3b1b / 3b1b/manim

Using ManimGL with pymunk for physics videos

Aperta
#1,707 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
bug
Lingua principale
Python
Stelle
93.8k
Fork
7.7k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Hello. I was trying to create physics animations with Manim and pymunk. I've the following file that I created for importing it to every Python file which corresponds to a physics video.

```python
import numpy as np
import pymunk
from manimlib.constants import RIGHT, UP
from manimlib.mobject.geometry import Circle, Line, Polygon, Rectangle
from manimlib.mobject.mobject import Group, Mobject
from manimlib.mobject.types.vectorized_mobject import VGroup, VMobject
from manimlib.scene.scene import Scene
from manimlib.utils.space_ops import angle_between_vectors
# based on manim-physics (https://github.com/Matheart/manim-physics)

class SpaceMobject(Mobject):

def __init__(self, gravity=(0, -9.81), **kwargs):
super().__init__(**kwargs)
self.space = pymunk.Space()
self.space.gravity = gravity
self.space.sleep_time_threshold = 5

class SpaceScene(Scene):
GRAVITY = (0, -9.81)

def __init__(self, **kwargs):
self.space = SpaceMobject(gravity=self.GRAVITY)
super().__init__(**kwargs)

def setup(self):
self.add(self.space)
self.space.add_updater(_step)

def add_body(self, body:VMobject):
if body.body != self.space.space.static_body:
self.space.space.add(body.body)
self.space.space.add(body.shape)

def make_rigid_body(
self,
*mobs: VMobject,
elasticity: float = 0.8,
density: float = 1,
friction: float = 0.8,
):
for mob in mobs:
if isinstance(mob, VGroup):
mobs -= mob
return self.make_rigid_body(*mob, *mobs)
if not hasattr(mob, "body"):
parts = mob.family_members_with_points()
for p in parts:
self.add(p)
p.body = pymunk.Body()
p.body.position = p.get_x(), p.get_y()
get_angle(p)
if not hasattr(p, "angle"):
p.angle = 0
p.body.angle = p.angle
get_shape(p)
p.shape.density = density
p.shape.elasticity = elasticity
p.shape.friction = friction
p.spacescene = self

self.add_body(p)
p.add_updater(_simulate)

else:
if mob.body.is_sleeping:
mob.body.activate()

def make_static_body(
self, *mobs: VMobject, elasticity: float = 1, friction: float = 0.8
) -> None:
for mob in mobs:
if isinstance(mob, VGroup):
mobs -= mob
return self.make_static_body(*mob, *mobs)
mob.body = self.space.space.static_body
get_shape(mob)
mob.shape.elasticity = elasticity
mob.shape.friction = friction
self.add_body(mob)

def stop_rigidity(self, *mobs: VMobject) -> None:
for mob in mobs:
if isinstance(mob, VGroup):
self.stop_rigidity(*mob)
if hasattr(mob, "body"):
mob.body.sleep()

def stop_physics(self):
for mob in self.mobjects:
if _simulate in mob.get_updaters():
mob.remove_updater(_simulate)
self.remove(self.space)

def _step(space, dt):
space.space.step(dt)

def _simulate(b):
x, y = b.body.position
b.move_to(x * RIGHT + y * UP)
b.rotate(b.body.angle - b.angle)
b.angle = b.body.angle

def get_shape(mob: VMobject) -> None:
if isinstance(mob, Circle):
mob.shape = pymunk.Circle(body=mob.body, radius=mob.radius)
elif isinstance(mob, Line):
mob.shape = pymunk.Segment(
mob.body,
(mob.get_start()[0], mob.get_start()[1]),
(mob.get_end()[0], mob.get_end()[1]),
mob.get_stroke_width() - 3.95,
)
elif issubclass(type(mob), Rectangle):
width = np.linalg.norm(mob.get_vertices()[1] - mob.get_vertices()[0])
height = np.linalg.norm(mob.get_vertices()[2] - mob.get_vertices()[1])
mob.shape = pymunk.Poly.create_box(mob.body, (width, height))
elif issubclass(type(mob), Polygon):
vertices = [(a, b) for a, b, c in mob.get_vertices() - mob.get_center()]
mob.shape = pymunk.Poly(mob.body, vertices)
else:
mob.shape = pymunk.Poly.create_box(mob.body, (mob.get_width(), mob.get_height()))

def get_angle(mob: VMobject) -> None:
if issubclass(type(mob), Polygon):
vec1 = mob.get_vertices()[0] - mob.get_vertices()[1]
vec2 = type(mob)().get_vertices()[0] - type(mob)().get_vertices()[1]
mob.angle = angle_between_vectors(vec1, vec2)
elif isinstance(mob, Line):
mob.angle = mob.get_angle()
```

This code is already imported to the code of the universal import line.

```python
from manimlib import *
from h2o.calculus_basics import *
from h2o.physics_basics import * # this is the previous code file
from h2o.logo import *
```

I've imported it to the following Python code:

```python
import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

from h2o_manim_basics import *

class WhatIsCalculus(SpaceScene):

def construct(self):
self.show_dot_and_fall()

def show_dot_and_fall(self):
dot = Dot().set_color(RED).to_edge(UP)
line = Line(LEFT, RIGHT).scale(6).to_edge(DOWN)
self.play(ShowCreation(line))
self.make_static_body(line)
self.play(ShowCreation(dot))
self.wait()
self.make_rigid_body(dot)
self.wait(5)
```
Also I'll show my custom_config.yml if it's useful.

```yml
directories:
mirror_module_path: True
output: "/Users/benja/Programming/manim_gl/h2o/videos"
raster_images: "/Users/benja/Programming/manim_gl/h2o/images/raster"
vector_images: "/Users/benja/Programming/manim_gl/h2o/images/vector"
sounds: "/Users/benja/Programming/manim_gl/h2o/sounds"
data: "/Users/benja/Programming/manim_gl/h2o/data"
temporary_storage: "/Users/benja/Programming/manim_gl/h2o/manim_cache"
universal_import_line: "from h2o_manim_basics import *"
# tex:
# executable: "xelatex -no-pdf"
# template_file: "ctex_template.tex"
# intermediate_filetype: "xdv"
style:
font: "CMU Serif"
background_color: "#000000"
camera_qualities:
high:
resolution: "1920x1080"
frame_rate: 60
default_quality: "high"
window_position: UR
window_monitor: 0
full_screen: False
```

It worked perfectly when it's not rendering to file. See the video I've recorded.

https://user-images.githubusercontent.com/94720291/149561223-814261e9-9160-4847-8982-3e7e1080d5df.mp4

However, when writing to a file this is the result.

https://user-images.githubusercontent.com/94720291/149561460-710f2c17-6c16-462b-bc1a-b0b55da90e08.mp4

I think this is a ManimGL bug since it works perfectly when displaying it in a pyglet window, but it's not OK when writing to a MP4 file.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.