diff --git a/manimlib/mobject/mobject.py b/manimlib/mobject/mobject.py index c9c04138..1d994a9e 100644 --- a/manimlib/mobject/mobject.py +++ b/manimlib/mobject/mobject.py @@ -41,6 +41,9 @@ class Mobject(Container): "frag_shader_file": "", "render_primative": moderngl.TRIANGLE_STRIP, "texture_path": "", + "shader_dtype": [ + ('point', np.float32, (3,)), + ] } def __init__(self, **kwargs): @@ -55,6 +58,7 @@ class Mobject(Container): self.reset_points() self.init_points() self.init_colors() + self.init_shader_data() def __str__(self): return str(self.name) @@ -110,7 +114,7 @@ class Mobject(Container): if camera is None: from manimlib.camera.camera import Camera camera = Camera() - camera.capture_mobject(self) + camera.capture(self) return camera.get_image() def show(self, camera=None): @@ -1125,6 +1129,18 @@ class Mobject(Container): pass # For shaders + def init_shader_data(self): + self.shader_data = np.zeros(len(self.points), dtype=self.shader_dtype) + + def get_shader_data_array(self, size, name="shader_data"): + # If possible, try to populate an existing array, rather + # than recreating it each frame + arr = getattr(self, name) + if arr.size != size: + new_arr = np.resize(arr, size) + setattr(self, name, new_arr) + return new_arr + return arr def get_shader_info_list(self): return [self.get_shader_info()] diff --git a/manimlib/mobject/types/image_mobject.py b/manimlib/mobject/types/image_mobject.py index 3f725805..d50774f6 100644 --- a/manimlib/mobject/types/image_mobject.py +++ b/manimlib/mobject/types/image_mobject.py @@ -15,6 +15,11 @@ class ImageMobject(Mobject): "opacity": 1, "vert_shader_file": "image_vert.glsl", "frag_shader_file": "image_frag.glsl", + "shader_dtype": [ + ('point', np.float32, (3,)), + ('im_coords', np.float32, (2,)), + ('opacity', np.float32, (1,)), + ] } def __init__(self, filename, **kwargs): @@ -37,17 +42,10 @@ class ImageMobject(Mobject): self.set_opacity(self.opacity) def get_shader_data(self): - dtype = [ - ('point', np.float32, (3,)), - ('im_coords', np.float32, (2,)), - ('opacity', np.float32, (1,)), - ] - - data = np.zeros(len(self.points), dtype=dtype) + data = self.get_shader_data_array(len(self.points)) data["point"] = self.points data["im_coords"] = self.im_coords data["opacity"] = self.opacity - return data def set_opacity(self, alpha, family=True): diff --git a/manimlib/mobject/types/vectorized_mobject.py b/manimlib/mobject/types/vectorized_mobject.py index fb27d667..b2b4371d 100644 --- a/manimlib/mobject/types/vectorized_mobject.py +++ b/manimlib/mobject/types/vectorized_mobject.py @@ -57,11 +57,22 @@ class VMobject(Mobject): "joint_type": "auto", "render_primative": moderngl.TRIANGLES, "triangulation_locked": False, + "fill_dtype": [ + ('point', np.float32, (3,)), + ('color', np.float32, (4,)), + ('fill_all', np.float32, (1,)), + ('orientation', np.float32, (1,)), + ], + "stroke_dtype": [ + ("point", np.float32, (3,)), + ("prev_point", np.float32, (3,)), + ("next_point", np.float32, (3,)), + ("stroke_width", np.float32, (1,)), + ("color", np.float32, (4,)), + ("joint_type", np.float32, (1,)), + ] } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - def get_group_class(self): return VGroup @@ -794,6 +805,10 @@ class VMobject(Mobject): return vmob # For shaders + def init_shader_data(self): + self.fill_data = np.zeros(len(self.points), dtype=self.fill_dtype) + self.stroke_data = np.zeros(len(self.points), dtype=self.stroke_dtype) + def get_shader_info_list(self): result = [] if self.get_fill_opacity() > 0: @@ -819,21 +834,12 @@ class VMobject(Mobject): return result def get_stroke_shader_data(self): - dtype = [ - ("point", np.float32, (3,)), - ("prev_point", np.float32, (3,)), - ("next_point", np.float32, (3,)), - ("stroke_width", np.float32, (1,)), - ("color", np.float32, (4,)), - ("joint_type", np.float32, (1,)), - ] joint_type_to_code = { "auto": 0, "round": 1, "bevel": 2, "miter": 3, } - points = self.points rgbas = self.get_stroke_rgbas() if len(rgbas) > 1: @@ -843,12 +849,12 @@ class VMobject(Mobject): if len(stroke_width) > 1: stroke_width = self.stretched_style_array_matching_points(stroke_width) - data = np.zeros(len(points), dtype=dtype) - data['point'] = points - data['prev_point'][:3] = points[-3:] - data['prev_point'][3:] = points[:-3] - data['next_point'][:-3] = points[3:] - data['next_point'][-3:] = points[:3] + data = self.get_shader_data_array(len(self.points), "stroke_data") + data['point'] = self.points + data['prev_point'][:3] = self.points[-3:] + data['prev_point'][3:] = self.points[:-3] + data['next_point'][:-3] = self.points[3:] + data['next_point'][-3:] = self.points[:3] data['stroke_width'][:, 0] = stroke_width data['color'] = rgbas data['joint_type'] = joint_type_to_code[self.joint_type] @@ -858,6 +864,7 @@ class VMobject(Mobject): for sm in self.family_members_with_points(): sm.triangulation_locked = False sm.saved_triangulation = sm.get_triangulation() + sm.saved_orientation = sm.get_orientation() sm.triangulation_locked = True return self @@ -873,6 +880,8 @@ class VMobject(Mobject): return sum((p0[:, 0] + p1[:, 0]) * (p1[:, 1] - p0[:, 1])) def get_orientation(self): + if self.triangulation_locked: + return self.saved_orientation return np.sign(self.get_signed_polygonal_area()) def get_triangulation(self, orientation=None): @@ -928,22 +937,15 @@ class VMobject(Mobject): return tri_indices def get_fill_shader_data(self): - dtype = [ - ('point', np.float32, (3,)), - ('color', np.float32, (4,)), - ('fill_all', np.float32, (1,)), - ('orientation', np.float32, (1,)), - ] - points = self.points orientation = self.get_orientation() tri_indices = self.get_triangulation(orientation) # TODO, best way to enable multiple colors? - rgbas = self.get_fill_rgbas() + rgbas = self.get_fill_rgbas()[:1] - data = np.zeros(len(tri_indices), dtype=dtype) + data = self.get_shader_data_array(len(tri_indices), "fill_data") data["point"] = points[tri_indices] data["color"] = rgbas # Assume the triangulation is such that the first n_points points