Move rendering to Mobject, and be smarter about caching data and vbo

This commit is contained in:
Grant Sanderson 2020-02-19 23:13:29 -08:00
parent 07cda695bb
commit b373b7936a
3 changed files with 56 additions and 21 deletions

View file

@ -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)

View file

@ -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():

View file

@ -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)