From 258bc2256ae5043c55b2b38e0202c14cb7fc47ee Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Thu, 26 Jan 2023 20:01:59 -0800 Subject: [PATCH] Provide a check that shader uniforms really need updating before setting value --- manimlib/mobject/mobject.py | 10 +++---- manimlib/mobject/types/vectorized_mobject.py | 5 ---- manimlib/shader_wrapper.py | 31 ++++++++++---------- manimlib/typing.py | 2 ++ 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/manimlib/mobject/mobject.py b/manimlib/mobject/mobject.py index 313517ee..c1774f95 100644 --- a/manimlib/mobject/mobject.py +++ b/manimlib/mobject/mobject.py @@ -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() diff --git a/manimlib/mobject/types/vectorized_mobject.py b/manimlib/mobject/types/vectorized_mobject.py index e83c76e3..2260fc2e 100644 --- a/manimlib/mobject/types/vectorized_mobject.py +++ b/manimlib/mobject/types/vectorized_mobject.py @@ -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] diff --git a/manimlib/shader_wrapper.py b/manimlib/shader_wrapper.py index aa733f8e..d4dc4889 100644 --- a/manimlib/shader_wrapper.py +++ b/manimlib/shader_wrapper.py @@ -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) diff --git a/manimlib/typing.py b/manimlib/typing.py index d4b68b3f..6ef9d22e 100644 --- a/manimlib/typing.py +++ b/manimlib/typing.py @@ -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. #