mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 04:57:46 +00:00
Move rendering to Mobject, and be smarter about caching data and vbo
This commit is contained in:
parent
07cda695bb
commit
b373b7936a
3 changed files with 56 additions and 21 deletions
|
|
@ -211,26 +211,16 @@ class Camera(object):
|
|||
|
||||
# Rendering
|
||||
def capture(self, *mobjects, **kwargs):
|
||||
shader_infos = it.chain(*[
|
||||
mob.get_shader_info_list()
|
||||
for mob in mobjects
|
||||
])
|
||||
# TODO, batching works well when the mobjects are already organized,
|
||||
# but can we somehow use z-buffering to better effect here?
|
||||
batches = batch_by_property(shader_infos, shader_info_to_id)
|
||||
|
||||
for info_group, sid in batches:
|
||||
shader = self.get_shader(sid)
|
||||
data = np.hstack([info["data"] for info in info_group])
|
||||
render_primative = int(info_group[0]["render_primative"])
|
||||
self.render_from_shader(shader, data, render_primative)
|
||||
for mobject in mobjects:
|
||||
mobject.render(camera=self)
|
||||
|
||||
# Shaders
|
||||
def init_shaders(self):
|
||||
# Initialize with the null id going to None
|
||||
self.id_to_shader = {"": None}
|
||||
|
||||
def get_shader(self, sid):
|
||||
def get_shader(self, shader_info):
|
||||
sid = shader_info_to_id(shader_info)
|
||||
if sid not in self.id_to_shader:
|
||||
info = shader_id_to_info(sid)
|
||||
shader = self.ctx.program(
|
||||
|
|
@ -288,10 +278,3 @@ class Camera(object):
|
|||
texture.use(location=tid)
|
||||
self.path_to_texture_id[path] = tid
|
||||
return self.path_to_texture_id[path]
|
||||
|
||||
def render_from_shader(self, shader, data, render_primative):
|
||||
if data is None or shader is None or len(data) == 0:
|
||||
return
|
||||
vbo = self.ctx.buffer(data.tobytes())
|
||||
vao = self.ctx.simple_vertex_array(shader, vbo, *data.dtype.names)
|
||||
vao.render(render_primative)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ class Mobject(Container):
|
|||
self.name = self.__class__.__name__
|
||||
self.updaters = []
|
||||
self.updating_suspended = False
|
||||
self.vbo = None
|
||||
self.shader_data_is_locked = False
|
||||
|
||||
self.reset_points()
|
||||
self.init_points()
|
||||
|
|
@ -1152,6 +1154,14 @@ class Mobject(Container):
|
|||
return new_arr
|
||||
return arr
|
||||
|
||||
def lock_shader_data(self):
|
||||
self.shader_data_is_locked = False
|
||||
self.saved_shader_info_list = self.get_shader_info_list()
|
||||
self.shader_data_is_locked = True
|
||||
|
||||
def unlock_shader_data(self):
|
||||
self.shader_data_is_locked = False
|
||||
|
||||
def get_shader_info_list(self):
|
||||
shader_infos = it.chain(
|
||||
[self.get_shader_info()],
|
||||
|
|
@ -1185,6 +1195,32 @@ class Mobject(Container):
|
|||
# Must return a structured numpy array
|
||||
return self.shader_data
|
||||
|
||||
def get_vbo(self, ctx, data):
|
||||
d_bytes = data.tobytes()
|
||||
if self.vbo is None or self.vbo.size != len(d_bytes):
|
||||
self.vbo = ctx.buffer(d_bytes)
|
||||
else:
|
||||
self.vbo.write(d_bytes)
|
||||
return self.vbo
|
||||
|
||||
def render(self, camera):
|
||||
if self.shader_data_is_locked:
|
||||
info_list = self.saved_shader_info_list
|
||||
else:
|
||||
info_list = self.get_shader_info_list()
|
||||
|
||||
for shader_info in info_list:
|
||||
data = shader_info["data"]
|
||||
if data is None or len(data) == 0:
|
||||
continue
|
||||
shader = camera.get_shader(shader_info)
|
||||
if shader is None:
|
||||
continue
|
||||
render_primative = int(shader_info["render_primative"])
|
||||
vbo = self.get_vbo(camera.ctx, data)
|
||||
vao = camera.ctx.simple_vertex_array(shader, vbo, *data.dtype.names)
|
||||
vao.render(render_primative)
|
||||
|
||||
# Errors
|
||||
def throw_error_if_no_points(self):
|
||||
if self.has_no_points():
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import inspect
|
|||
import random
|
||||
import warnings
|
||||
import platform
|
||||
import itertools as it
|
||||
|
||||
from tqdm import tqdm as ProgressDisplay
|
||||
import numpy as np
|
||||
|
|
@ -389,6 +390,18 @@ class Scene(Container):
|
|||
self.num_plays += 1
|
||||
return wrapper
|
||||
|
||||
def lock_static_mobjects(self, animations):
|
||||
movers = list(it.chain(*[
|
||||
anim.mobject.get_family()
|
||||
for anim in animations
|
||||
]))
|
||||
for mobject in self.mobjects:
|
||||
if mobject in movers:
|
||||
continue
|
||||
if mobject.get_family_updaters():
|
||||
continue
|
||||
mobject.lock_shader_data()
|
||||
|
||||
def begin_animations(self, animations):
|
||||
curr_mobjects = self.get_mobject_family_members()
|
||||
for animation in animations:
|
||||
|
|
@ -420,6 +433,8 @@ class Scene(Container):
|
|||
self.mobjects_from_last_animation = [
|
||||
anim.mobject for anim in animations
|
||||
]
|
||||
for mobject in self.mobjects:
|
||||
mobject.unlock_shader_data()
|
||||
if self.skip_animations:
|
||||
# TODO, run this call in for each animation?
|
||||
self.update_mobjects(self.get_run_time(animations))
|
||||
|
|
@ -432,6 +447,7 @@ class Scene(Container):
|
|||
warnings.warn("Called Scene.play with no animations")
|
||||
return
|
||||
animations = self.anims_from_play_args(*args, **kwargs)
|
||||
self.lock_static_mobjects(animations)
|
||||
self.begin_animations(animations)
|
||||
self.progress_through_animations(animations)
|
||||
self.finish_animations(animations)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue