Skip to content

Commit 9b98fe5

Browse files
chopan050pre-commit-ci[bot]MrDiver
authored
[EXPERIMENTAL] Mobject shader cleanup + Scene changes + Undo orientation input in vertex shader + Transparency Fix (#3474)
* Updated Scene.remove * Updated Scene.replace * When shader file is missing, log its absolute path * Undo adding 'orientation' in vert.glsl, revert to 'unit_normal' in OpenGLVMobject * Added removed docstring to Scene.replace * Removed and rewrote multiple OpenGL(V)Mobject methods * Fixed OpenGLVMobject.get_style() * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fixing transparency and generator bug * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: MrDiver <[email protected]>
1 parent eb1ff92 commit 9b98fe5

File tree

11 files changed

+271
-376
lines changed

11 files changed

+271
-376
lines changed

example_scenes/new_test_new.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import time
2+
3+
import numpy as np
4+
import pyglet
5+
from PIL import Image
6+
from pyglet import shapes
7+
from pyglet.gl import Config
8+
from pyglet.window import Window
9+
10+
import manim.utils.color.manim_colors as col
11+
from manim._config import config, tempconfig
12+
from manim.animation.creation import Create, DrawBorderThenFill, Write
13+
from manim.animation.fading import FadeIn
14+
from manim.animation.transform import Transform
15+
from manim.camera.camera import OpenGLCameraFrame
16+
from manim.constants import LEFT, OUT, RIGHT, UP
17+
from manim.mobject.geometry.arc import Circle
18+
from manim.mobject.geometry.polygram import Square
19+
from manim.mobject.logo import ManimBanner
20+
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
21+
from manim.mobject.text.numbers import DecimalNumber
22+
from manim.mobject.text.text_mobject import Text
23+
from manim.renderer.opengl_renderer import OpenGLRenderer
24+
25+
26+
def progress_through_animations(animations):
27+
dt = t - last_t
28+
last_t = t
29+
for animation in animations:
30+
animation.update_mobjects(dt)
31+
alpha = t / animation.run_time
32+
animation.interpolate(alpha)
33+
self.update_frame(dt)
34+
self.emit_frame()
35+
36+
37+
if __name__ == "__main__":
38+
with tempconfig({"renderer": "opengl"}):
39+
win = Window(
40+
width=1920,
41+
height=1080,
42+
vsync=True,
43+
config=Config(double_buffer=True, samples=0),
44+
)
45+
renderer = OpenGLRenderer(1920, 1080, background_color=col.GRAY)
46+
# vm = OpenGLVMobject([col.RED, col.GREEN])
47+
vm = (
48+
Circle(
49+
radius=1,
50+
stroke_color=col.YELLOW,
51+
)
52+
.shift(3 * RIGHT + OUT)
53+
.set_opacity(0.6)
54+
)
55+
vm2 = Square(stroke_color=col.GREEN, fill_opacity=0, stroke_opacity=1).move_to(
56+
(0, 0, -0.5)
57+
)
58+
vm3 = ManimBanner().set_opacity(0.6)
59+
vm4 = (
60+
Circle(0.5, col.GREEN)
61+
.set_opacity(0.6)
62+
.shift(OUT)
63+
.set_fill(col.BLUE, opacity=0.2)
64+
)
65+
# vm.set_points_as_corners([[-1920/2, 0, 0], [1920/2, 0, 0], [0, 1080/2, 0]])
66+
# print(vm.color)
67+
# print(vm.fill_color)
68+
# print(vm.stroke_color)
69+
70+
clock_mobject = DecimalNumber(0.0).shift(4 * LEFT + 2.5 * UP)
71+
clock_mobject.fix_in_frame()
72+
73+
camera = OpenGLCameraFrame()
74+
camera.save_state()
75+
# renderer.init_camera(camera)
76+
77+
# renderer.render(camera, [vm, vm2])
78+
# image = renderer.get_pixels()
79+
# print(image.shape)
80+
# Image.fromarray(image, "RGBA").show()
81+
# exit(0)
82+
renderer.use_window()
83+
84+
clock = pyglet.clock.get_default()
85+
86+
def update_circle(dt):
87+
vm.move_to((np.sin(dt) * 4, np.cos(dt) * 4, -1))
88+
89+
def p2m(x, y, z):
90+
from manim._config import config
91+
92+
return (
93+
config.frame_width * (x / config.pixel_width - 0.5),
94+
config.frame_height * (y / config.pixel_height - 0.5),
95+
z,
96+
)
97+
98+
@win.event
99+
def on_close():
100+
win.close()
101+
102+
@win.event
103+
def on_mouse_motion(x, y, dx, dy):
104+
# vm.move_to((14.2222 * (x / 1920 - 0.5), 8 * (y / 1080 - 0.5), 0))
105+
# camera.move_to(p2m(x,y,camera.get_center()[2]))
106+
from scipy.spatial.transform import Rotation
107+
108+
camera.set_orientation(
109+
Rotation.from_rotvec(
110+
(-UP * (x / 1920 - 0.5) + RIGHT * (y / 1080 - 0.5)) * 2 * 3.1415
111+
)
112+
)
113+
# vm.set_color(col.RED.interpolate(col.GREEN,x/1920))
114+
# print(x,y)
115+
116+
@win.event
117+
def on_draw():
118+
dt = clock.update_time()
119+
renderer.render(camera, [vm2, vm3, vm4, clock_mobject, vm])
120+
# update_circle(counter)
121+
122+
@win.event
123+
def on_resize(width, height):
124+
super(Window, win).on_resize(width, height)
125+
126+
# pyglet.app.run()
127+
has_started = False
128+
is_finished = False
129+
130+
run_time = 5
131+
new_vm = Square(fill_color=col.GREEN, stroke_color=col.BLUE).shift(
132+
2.5 * RIGHT - UP + 2 * OUT
133+
)
134+
animation = DrawBorderThenFill(vm3, run_time=run_time)
135+
136+
real_time = 0
137+
virtual_time = 0
138+
start_timestamp = time.time()
139+
dt = 1 / 30
140+
141+
while True:
142+
# pyglet.app.platform_event_loop.step()
143+
win.switch_to()
144+
if not has_started:
145+
animation.begin()
146+
has_started = True
147+
148+
real_time = time.time() - start_timestamp
149+
while virtual_time < real_time:
150+
virtual_time += dt
151+
if not is_finished:
152+
if virtual_time >= run_time:
153+
animation.finish()
154+
has_finished = True
155+
else:
156+
animation.update_mobjects(dt)
157+
animation.interpolate(virtual_time / run_time)
158+
# update_circle(virtual_time)
159+
clock_mobject.set_value(virtual_time)
160+
win.dispatch_event("on_draw")
161+
win.dispatch_events()
162+
win.flip()

manim/mobject/opengl/opengl_mobject.py

Lines changed: 3 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,6 @@ def __init__(
174174
self.init_points()
175175
self.color = ManimColor.parse(color)
176176
self.init_colors()
177-
self.init_shader_data()
178-
179-
if self.depth_test:
180-
self.apply_depth_test()
181177

182178
@classmethod
183179
def __init_subclass__(cls, **kwargs):
@@ -2639,8 +2635,6 @@ def align_data_and_family(self, mobject):
26392635
self.align_data(mobject)
26402636

26412637
def align_data(self, mobject) -> None:
2642-
# In case any data arrays get resized when aligned to shader data
2643-
self.refresh_shader_data()
26442638
for mob1, mob2 in zip(self.get_family(), mobject.get_family()):
26452639
# Separate out how points are treated so that subclasses
26462640
# can handle that case differently if they choose
@@ -2731,24 +2725,9 @@ def construct(self):
27312725
27322726
self.add(dotL, dotR, dotMiddle)
27332727
"""
2734-
for key in self.data:
2735-
if key in self.locked_data_keys:
2736-
continue
2737-
if len(self.data[key]) == 0: # type: ignore
2738-
continue
2739-
if key not in mobject1.data or key not in mobject2.data:
2740-
continue
2741-
2742-
if key in ("points", "bounding_box"):
2743-
func = path_func
2744-
else:
2745-
func = interpolate
2746-
2747-
self.data[key][:] = func(mobject1.data[key], mobject2.data[key], alpha) # type: ignore
2748-
for key in self.uniforms:
2749-
self.uniforms[key] = interpolate( # type: ignore
2750-
mobject1.uniforms[key], mobject2.uniforms[key], alpha
2751-
)
2728+
# TODO: replace with list of attribute names with a locking system
2729+
self.points = path_func(mobject1.points, mobject2.points, alpha)
2730+
self.interpolate_color(mobject1, mobject2, alpha)
27522731
return self
27532732

27542733
def pointwise_become_partial(self, mobject, a, b):
@@ -2906,44 +2885,36 @@ def has_same_shape_as(self, mobject: OpenGLMobject) -> bool:
29062885
return bool(np.isclose(points1, points2).all())
29072886

29082887
# Operations touching shader uniforms
2909-
2910-
@affects_shader_info_id
29112888
def fix_in_frame(self) -> Self:
29122889
self.uniforms["is_fixed_in_frame"] = float(1.0)
29132890
self.is_fixed_in_frame = True
29142891
return self
29152892

2916-
@affects_shader_info_id
29172893
def fix_orientation(self) -> Self:
29182894
self.uniforms["is_fixed_orientation"] = float(1.0)
29192895
self.is_fixed_orientation = True
29202896
self.fixed_orientation_center = tuple(self.get_center())
29212897
return self
29222898

2923-
@affects_shader_info_id
29242899
def unfix_from_frame(self) -> Self:
29252900
self.uniforms["is_fixed_in_frame"] = float(0.0)
29262901
self.is_fixed_in_frame = False
29272902
return self
29282903

2929-
@affects_shader_info_id
29302904
def unfix_orientation(self):
29312905
self.is_fixed_orientation = 0.0
29322906
self.fixed_orientation_center = (0, 0, 0)
29332907
return self
29342908

2935-
@affects_shader_info_id
29362909
def apply_depth_test(self):
29372910
self.depth_test = True
29382911
return self
29392912

2940-
@affects_shader_info_id
29412913
def deactivate_depth_test(self):
29422914
self.depth_test = False
29432915
return self
29442916

29452917
# Shader code manipulation
2946-
29472918
def replace_shader_code(self, old, new):
29482919
# TODO, will this work with VMobject structure, given
29492920
# that it does not simpler return shader_wrappers of
@@ -2988,47 +2959,6 @@ def set_color_by_xyz_func(
29882959
)
29892960
return self
29902961

2991-
# For shader data
2992-
def init_shader_data(self):
2993-
# TODO, only call this when needed?
2994-
self.shader_data = np.zeros(len(self.points), dtype=self.shader_dtype)
2995-
self.shader_indices = None
2996-
self.shader_wrapper = ShaderWrapper(
2997-
vert_data=self.shader_data,
2998-
shader_folder=self.shader_folder,
2999-
texture_paths=self.texture_paths,
3000-
depth_test=self.depth_test,
3001-
render_primitive=self.render_primitive,
3002-
)
3003-
3004-
def refresh_shader_wrapper_id(self):
3005-
self.shader_wrapper.refresh_id()
3006-
return self
3007-
3008-
def get_shader_wrapper(self):
3009-
self.shader_wrapper.vert_data = self.get_shader_data()
3010-
self.shader_wrapper.vert_indices = self.get_shader_vert_indices()
3011-
self.shader_wrapper.uniforms = self.get_shader_uniforms()
3012-
self.shader_wrapper.depth_test = self.depth_test
3013-
return self.shader_wrapper
3014-
3015-
def get_shader_wrapper_list(self):
3016-
shader_wrappers = it.chain(
3017-
[self.get_shader_wrapper()],
3018-
*(sm.get_shader_wrapper_list() for sm in self.submobjects),
3019-
)
3020-
batches = batch_by_property(shader_wrappers, lambda sw: sw.get_id())
3021-
3022-
result = []
3023-
for wrapper_group, _ in batches:
3024-
shader_wrapper = wrapper_group[0]
3025-
if not shader_wrapper.is_valid():
3026-
continue
3027-
shader_wrapper.combine_with(*wrapper_group[1:])
3028-
if len(shader_wrapper.vert_data) > 0:
3029-
result.append(shader_wrapper)
3030-
return result
3031-
30322962
def check_data_alignment(self, array, data_key):
30332963
# Makes sure that self.data[key] can be broadcast into
30342964
# the given array, meaning its length has to be either 1
@@ -3041,33 +2971,6 @@ def check_data_alignment(self, array, data_key):
30412971
)
30422972
return self
30432973

3044-
def get_resized_shader_data_array(self, length: int) -> np.ndarray:
3045-
# If possible, try to populate an existing array, rather
3046-
# than recreating it each frame
3047-
if len(self.shader_data) != length:
3048-
self.shader_data = resize_array(self.shader_data, length)
3049-
return self.shader_data
3050-
3051-
def read_data_to_shader(self, shader_data, shader_data_key, data_key):
3052-
if data_key in self.locked_data_keys:
3053-
return
3054-
self.check_data_alignment(shader_data, data_key)
3055-
shader_data[shader_data_key] = self.data[data_key]
3056-
3057-
def get_shader_data(self):
3058-
shader_data = self.get_resized_shader_data_array(self.get_num_points())
3059-
self.read_data_to_shader(shader_data, "point", "points")
3060-
return shader_data
3061-
3062-
def refresh_shader_data(self):
3063-
self.get_shader_data()
3064-
3065-
def get_shader_uniforms(self):
3066-
return self.uniforms
3067-
3068-
def get_shader_vert_indices(self):
3069-
return self.shader_indices
3070-
30712974
# Event Handlers
30722975
"""
30732976
Event handling follows the Event Bubbling model of DOM in javascript.

0 commit comments

Comments
 (0)