mirror of
https://github.com/3b1b/manim.git
synced 2025-07-31 05:52:34 +08:00
Have mobjects keep track of a consistent shader data array to avoid unneeded numpy initializing
This commit is contained in:
@ -41,6 +41,9 @@ class Mobject(Container):
|
|||||||
"frag_shader_file": "",
|
"frag_shader_file": "",
|
||||||
"render_primative": moderngl.TRIANGLE_STRIP,
|
"render_primative": moderngl.TRIANGLE_STRIP,
|
||||||
"texture_path": "",
|
"texture_path": "",
|
||||||
|
"shader_dtype": [
|
||||||
|
('point', np.float32, (3,)),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
@ -55,6 +58,7 @@ class Mobject(Container):
|
|||||||
self.reset_points()
|
self.reset_points()
|
||||||
self.init_points()
|
self.init_points()
|
||||||
self.init_colors()
|
self.init_colors()
|
||||||
|
self.init_shader_data()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.name)
|
return str(self.name)
|
||||||
@ -110,7 +114,7 @@ class Mobject(Container):
|
|||||||
if camera is None:
|
if camera is None:
|
||||||
from manimlib.camera.camera import Camera
|
from manimlib.camera.camera import Camera
|
||||||
camera = Camera()
|
camera = Camera()
|
||||||
camera.capture_mobject(self)
|
camera.capture(self)
|
||||||
return camera.get_image()
|
return camera.get_image()
|
||||||
|
|
||||||
def show(self, camera=None):
|
def show(self, camera=None):
|
||||||
@ -1125,6 +1129,18 @@ class Mobject(Container):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# For shaders
|
# 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):
|
def get_shader_info_list(self):
|
||||||
return [self.get_shader_info()]
|
return [self.get_shader_info()]
|
||||||
|
@ -15,6 +15,11 @@ class ImageMobject(Mobject):
|
|||||||
"opacity": 1,
|
"opacity": 1,
|
||||||
"vert_shader_file": "image_vert.glsl",
|
"vert_shader_file": "image_vert.glsl",
|
||||||
"frag_shader_file": "image_frag.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):
|
def __init__(self, filename, **kwargs):
|
||||||
@ -37,17 +42,10 @@ class ImageMobject(Mobject):
|
|||||||
self.set_opacity(self.opacity)
|
self.set_opacity(self.opacity)
|
||||||
|
|
||||||
def get_shader_data(self):
|
def get_shader_data(self):
|
||||||
dtype = [
|
data = self.get_shader_data_array(len(self.points))
|
||||||
('point', np.float32, (3,)),
|
|
||||||
('im_coords', np.float32, (2,)),
|
|
||||||
('opacity', np.float32, (1,)),
|
|
||||||
]
|
|
||||||
|
|
||||||
data = np.zeros(len(self.points), dtype=dtype)
|
|
||||||
data["point"] = self.points
|
data["point"] = self.points
|
||||||
data["im_coords"] = self.im_coords
|
data["im_coords"] = self.im_coords
|
||||||
data["opacity"] = self.opacity
|
data["opacity"] = self.opacity
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def set_opacity(self, alpha, family=True):
|
def set_opacity(self, alpha, family=True):
|
||||||
|
@ -57,11 +57,22 @@ class VMobject(Mobject):
|
|||||||
"joint_type": "auto",
|
"joint_type": "auto",
|
||||||
"render_primative": moderngl.TRIANGLES,
|
"render_primative": moderngl.TRIANGLES,
|
||||||
"triangulation_locked": False,
|
"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):
|
def get_group_class(self):
|
||||||
return VGroup
|
return VGroup
|
||||||
|
|
||||||
@ -794,6 +805,10 @@ class VMobject(Mobject):
|
|||||||
return vmob
|
return vmob
|
||||||
|
|
||||||
# For shaders
|
# 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):
|
def get_shader_info_list(self):
|
||||||
result = []
|
result = []
|
||||||
if self.get_fill_opacity() > 0:
|
if self.get_fill_opacity() > 0:
|
||||||
@ -819,21 +834,12 @@ class VMobject(Mobject):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def get_stroke_shader_data(self):
|
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 = {
|
joint_type_to_code = {
|
||||||
"auto": 0,
|
"auto": 0,
|
||||||
"round": 1,
|
"round": 1,
|
||||||
"bevel": 2,
|
"bevel": 2,
|
||||||
"miter": 3,
|
"miter": 3,
|
||||||
}
|
}
|
||||||
points = self.points
|
|
||||||
|
|
||||||
rgbas = self.get_stroke_rgbas()
|
rgbas = self.get_stroke_rgbas()
|
||||||
if len(rgbas) > 1:
|
if len(rgbas) > 1:
|
||||||
@ -843,12 +849,12 @@ class VMobject(Mobject):
|
|||||||
if len(stroke_width) > 1:
|
if len(stroke_width) > 1:
|
||||||
stroke_width = self.stretched_style_array_matching_points(stroke_width)
|
stroke_width = self.stretched_style_array_matching_points(stroke_width)
|
||||||
|
|
||||||
data = np.zeros(len(points), dtype=dtype)
|
data = self.get_shader_data_array(len(self.points), "stroke_data")
|
||||||
data['point'] = points
|
data['point'] = self.points
|
||||||
data['prev_point'][:3] = points[-3:]
|
data['prev_point'][:3] = self.points[-3:]
|
||||||
data['prev_point'][3:] = points[:-3]
|
data['prev_point'][3:] = self.points[:-3]
|
||||||
data['next_point'][:-3] = points[3:]
|
data['next_point'][:-3] = self.points[3:]
|
||||||
data['next_point'][-3:] = points[:3]
|
data['next_point'][-3:] = self.points[:3]
|
||||||
data['stroke_width'][:, 0] = stroke_width
|
data['stroke_width'][:, 0] = stroke_width
|
||||||
data['color'] = rgbas
|
data['color'] = rgbas
|
||||||
data['joint_type'] = joint_type_to_code[self.joint_type]
|
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():
|
for sm in self.family_members_with_points():
|
||||||
sm.triangulation_locked = False
|
sm.triangulation_locked = False
|
||||||
sm.saved_triangulation = sm.get_triangulation()
|
sm.saved_triangulation = sm.get_triangulation()
|
||||||
|
sm.saved_orientation = sm.get_orientation()
|
||||||
sm.triangulation_locked = True
|
sm.triangulation_locked = True
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -873,6 +880,8 @@ class VMobject(Mobject):
|
|||||||
return sum((p0[:, 0] + p1[:, 0]) * (p1[:, 1] - p0[:, 1]))
|
return sum((p0[:, 0] + p1[:, 0]) * (p1[:, 1] - p0[:, 1]))
|
||||||
|
|
||||||
def get_orientation(self):
|
def get_orientation(self):
|
||||||
|
if self.triangulation_locked:
|
||||||
|
return self.saved_orientation
|
||||||
return np.sign(self.get_signed_polygonal_area())
|
return np.sign(self.get_signed_polygonal_area())
|
||||||
|
|
||||||
def get_triangulation(self, orientation=None):
|
def get_triangulation(self, orientation=None):
|
||||||
@ -928,22 +937,15 @@ class VMobject(Mobject):
|
|||||||
return tri_indices
|
return tri_indices
|
||||||
|
|
||||||
def get_fill_shader_data(self):
|
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
|
points = self.points
|
||||||
|
|
||||||
orientation = self.get_orientation()
|
orientation = self.get_orientation()
|
||||||
tri_indices = self.get_triangulation(orientation)
|
tri_indices = self.get_triangulation(orientation)
|
||||||
|
|
||||||
# TODO, best way to enable multiple colors?
|
# 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["point"] = points[tri_indices]
|
||||||
data["color"] = rgbas
|
data["color"] = rgbas
|
||||||
# Assume the triangulation is such that the first n_points points
|
# Assume the triangulation is such that the first n_points points
|
||||||
|
Reference in New Issue
Block a user