Provide a check that shader uniforms really need updating before setting value

This commit is contained in:
Grant Sanderson 2023-01-26 20:01:59 -08:00
parent acdc2654d3
commit 258bc2256a
4 changed files with 23 additions and 25 deletions

View file

@ -50,7 +50,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Callable, Iterable, Union, Tuple
import numpy.typing as npt
from manimlib.typing import ManimColor, Vect3, Vect4, Vect3Array
from manimlib.typing import ManimColor, Vect3, Vect4, Vect3Array, UniformDict
from moderngl.context import Context
TimeBasedUpdater = Callable[["Mobject", float], "Mobject" | None]
@ -131,7 +131,7 @@ class Mobject(object):
self.data = np.zeros(length, dtype=self.shader_dtype)
def init_uniforms(self):
self.uniforms: dict[str, float | np.ndarray] = {
self.uniforms: UniformDict = {
"is_fixed_in_frame": float(self.is_fixed_in_frame),
"shading": np.array(self.shading, dtype=float),
}
@ -1894,7 +1894,7 @@ class Mobject(object):
self.shader_wrapper.vert_data = self.get_shader_data()
self.shader_wrapper.vert_indices = self.get_shader_vert_indices()
self.shader_wrapper.uniforms.update(self.get_uniforms())
self.shader_wrapper.update_program_uniforms(self.get_uniforms())
self.shader_wrapper.depth_test = self.depth_test
return self.shader_wrapper
@ -1931,8 +1931,8 @@ class Mobject(object):
shader_wrapper.generate_vao()
self._data_has_changed = False
for shader_wrapper in self.shader_wrappers:
shader_wrapper.uniforms.update(self.get_uniforms())
shader_wrapper.uniforms.update(camera_uniforms)
shader_wrapper.update_program_uniforms(self.get_uniforms())
shader_wrapper.update_program_uniforms(camera_uniforms, universal=True)
shader_wrapper.pre_render()
shader_wrapper.render()

View file

@ -1264,11 +1264,6 @@ class VMobject(Mobject):
self.fill_shader_wrapper.read_in(fill_datas, fill_indices or None),
self.stroke_shader_wrapper.read_in(stroke_datas),
]
for sw in shader_wrappers:
# Assume uniforms of the first family member
sw.uniforms.update(family[0].get_uniforms())
sw.depth_test = family[0].depth_test
return [sw for sw in shader_wrappers if len(sw.vert_data) > 0]

View file

@ -7,7 +7,6 @@ import re
import OpenGL.GL as gl
import moderngl
import numpy as np
from functools import lru_cache
from manimlib.utils.iterables import resize_array
from manimlib.utils.shaders import get_shader_code_from_file
@ -20,7 +19,8 @@ from manimlib.utils.shaders import release_texture
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import List, Optional
from typing import List, Optional, Dict
from manimlib.typing import UniformDict
# Mobjects that should be rendered with
@ -37,7 +37,7 @@ class ShaderWrapper(object):
vert_data: np.ndarray,
vert_indices: Optional[np.ndarray] = None,
shader_folder: Optional[str] = None,
uniforms: Optional[dict[str, float | np.ndarray]] = None, # A dictionary mapping names of uniform variables
uniforms: Optional[UniformDict] = None, # A dictionary mapping names of uniform variables
texture_paths: Optional[dict[str, str]] = None, # A dictionary mapping names to filepaths for textures.
depth_test: bool = False,
render_primitive: int = moderngl.TRIANGLE_STRIP,
@ -47,12 +47,13 @@ class ShaderWrapper(object):
self.vert_indices = (vert_indices or np.zeros(0)).astype(int)
self.vert_attributes = vert_data.dtype.names
self.shader_folder = shader_folder
self.uniforms = dict(uniforms or {})
self.uniforms: UniformDict = dict()
self.depth_test = depth_test
self.render_primitive = render_primitive
self.init_program_code()
self.init_program()
self.update_program_uniforms(uniforms or dict())
if texture_paths is not None:
self.init_textures(texture_paths)
self.refresh_id()
@ -93,7 +94,7 @@ class ShaderWrapper(object):
np.all(self.vert_indices == shader_wrapper.vert_indices),
self.shader_folder == shader_wrapper.shader_folder,
all(
np.all(self.uniforms[key] == shader_wrapper.uniforms[key])
self.uniforms[key] == shader_wrapper.uniforms[key]
for key in self.uniforms
),
self.depth_test == shader_wrapper.depth_test,
@ -105,8 +106,6 @@ class ShaderWrapper(object):
result.ctx = self.ctx
result.vert_data = self.vert_data.copy()
result.vert_indices = self.vert_indices.copy()
if self.uniforms:
result.uniforms = {key: np.array(value) for key, value in self.uniforms.items()}
result.vao = None
result.vbo = None
result.ibo = None
@ -217,20 +216,23 @@ class ShaderWrapper(object):
def pre_render(self):
self.set_ctx_depth_test(self.depth_test)
self.set_ctx_clip_plane(self.use_clip_plane())
self.update_program_uniforms()
def render(self):
assert(self.vao is not None)
self.vao.render()
def update_program_uniforms(self):
def update_program_uniforms(self, uniforms: UniformDict, universal: bool = False):
if self.program is None:
return
for name, value in self.uniforms.items():
if name in self.program:
if isinstance(value, np.ndarray) and value.ndim > 0:
value = tuple(value)
self.program[name].value = value
for name, value in uniforms.items():
if name not in self.program:
continue
if isinstance(value, np.ndarray) and value.ndim > 0:
value = tuple(value)
if universal and self.uniforms.get(name, None) == value:
continue
self.program[name].value = value
self.uniforms[name] = value
def get_vertex_buffer_object(self, refresh: bool = True):
if refresh:
@ -274,7 +276,6 @@ class FillShaderWrapper(ShaderWrapper):
):
super().__init__(ctx, *args, **kwargs)
def render(self):
vao = self.vao
assert(vao is not None)

View file

@ -19,6 +19,8 @@ if TYPE_CHECKING:
]
Selector = Union[SingleSelector, Iterable[SingleSelector]]
UniformDict = Dict[str, float | bool | np.ndarray | tuple]
# These are various alternate names for np.ndarray meant to specify
# certain shapes.
#