From 706838cae1340507a267c25a07fbc0e775f94eca Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Sat, 29 Jun 2024 19:03:27 -0500 Subject: [PATCH 1/6] Add a border to display_bounds components --- yt_idv/scene_components/base_component.py | 40 ++++++++++++++++++++++- yt_idv/shaders/known_uniforms.inc.glsl | 3 ++ yt_idv/shaders/passthrough.frag.glsl | 4 +++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/yt_idv/scene_components/base_component.py b/yt_idv/scene_components/base_component.py index 82baa8d7..e968d37d 100644 --- a/yt_idv/scene_components/base_component.py +++ b/yt_idv/scene_components/base_component.py @@ -59,6 +59,11 @@ class SceneComponent(traitlets.HasTraits): display_name = traitlets.Unicode(allow_none=True) + final_pass_vertex = ShaderTrait(allow_none=True).tag(shader_type="fragment") + final_pass_fragment = ShaderTrait(allow_none=True).tag(shader_type="vertex") + _final_pass = traitlets.Instance(ShaderProgram, allow_none=True) + _final_pass_invalid = True + # These attributes are cmap_min = traitlets.CFloat(None, allow_none=True) cmap_max = traitlets.CFloat(None, allow_none=True) @@ -217,6 +222,14 @@ def _colormap_vertex_default(self): def _colormap_fragment_default(self): return component_shaders[self.name][self.render_method]["second_fragment"] + @traitlets.default("final_pass_vertex") + def _final_pass_vertex_default(self): + return "passthrough" + + @traitlets.default("final_pass_fragment") + def _final_pass_fragment_default(self): + return "passthrough" + @traitlets.default("base_quad") def _default_base_quad(self): bq = SceneData( @@ -253,6 +266,16 @@ def program2(self): self._program2_invalid = False return self._program2 + @property + def final_pass(self): + if self._final_pass_invalid: + if self._final_pass is not None: + self._final_pass.delete_program() + self._final_pass = ShaderProgram( + self.final_pass_vertex, self.final_pass_fragment + ) + return self._final_pass + def _set_iso_uniforms(self, p): # these could be handled better by watching traits. p._set_uniform("iso_num_layers", int(len(self.iso_layers))) @@ -268,6 +291,10 @@ def _set_iso_uniforms(self, p): def run_program(self, scene): # Store this info, because we need to render into a framebuffer that is the # right size. + if self.display_bounds != (0.0, 1.0, 0.0, 1.0): + draw_boundary = 0.002 + else: + draw_boundary = 0.0 x0, y0, w, h = GL.glGetIntegerv(GL.GL_VIEWPORT) GL.glViewport(0, 0, w, h) if not self.visible: @@ -303,6 +330,13 @@ def run_program(self, scene): GL.glViewport(x0, y0, w, h) GL.glDrawArrays(GL.GL_TRIANGLES, 0, 6) + if draw_boundary > 0.0: + with self.final_pass.enable() as p3: + p3._set_uniform("draw_boundary", float(draw_boundary)) + with self.base_quad.vertex_array.bind(p3): + GL.glViewport(x0, y0, w, h) + GL.glDrawArrays(GL.GL_TRIANGLES, 0, 6) + def draw(self, scene, program): raise NotImplementedError @@ -373,12 +407,16 @@ def _recompile_shader(self) -> bool: "fragment_shader", "colormap_vertex", "colormap_fragment", + "final_pass_vertex", + "final_pass_fragment", ) for shader_name in shaders: s = getattr(self, shader_name, None) if s: s.delete_shader() - self._program1_invalid = self._program2_invalid = True + self._program1_invalid = self._program2_invalid = self._final_pass_invalid = ( + True + ) return True def _render_isolayer_inputs(self, imgui) -> bool: diff --git a/yt_idv/shaders/known_uniforms.inc.glsl b/yt_idv/shaders/known_uniforms.inc.glsl index 220d5d15..e46bb4a4 100644 --- a/yt_idv/shaders/known_uniforms.inc.glsl +++ b/yt_idv/shaders/known_uniforms.inc.glsl @@ -62,3 +62,6 @@ uniform int iso_num_layers; uniform float iso_layers[32]; uniform float iso_layer_tol[32]; uniform float iso_alphas[32]; + +// draw outline control +uniform float draw_boundary; \ No newline at end of file diff --git a/yt_idv/shaders/passthrough.frag.glsl b/yt_idv/shaders/passthrough.frag.glsl index 63b0d77d..e5c963b8 100644 --- a/yt_idv/shaders/passthrough.frag.glsl +++ b/yt_idv/shaders/passthrough.frag.glsl @@ -5,5 +5,9 @@ out vec4 color; void main(){ color = texture(fb_tex, UV); color.a = 1.0; + vec2 d = abs(UV - vec2(0.5)); + if(0.5 - max(d.x, d.y) < draw_boundary) { + color = vec4(1.0, 1.0, 1.0, 0.5); + } gl_FragDepth = texture(db_tex, UV).r; } From 08c6af8c5474b9ac92403a83c1ebfa3ce5c319fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:04:42 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- yt_idv/shaders/known_uniforms.inc.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_idv/shaders/known_uniforms.inc.glsl b/yt_idv/shaders/known_uniforms.inc.glsl index e46bb4a4..4f2cb991 100644 --- a/yt_idv/shaders/known_uniforms.inc.glsl +++ b/yt_idv/shaders/known_uniforms.inc.glsl @@ -64,4 +64,4 @@ uniform float iso_layer_tol[32]; uniform float iso_alphas[32]; // draw outline control -uniform float draw_boundary; \ No newline at end of file +uniform float draw_boundary; From 5a07256d397b2c69fa45fa451d30bc50edc65f91 Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Sun, 30 Jun 2024 13:11:43 -0500 Subject: [PATCH 3/6] Use special purpose shader for borders --- yt_idv/scene_components/base_component.py | 2 +- yt_idv/shaders/display_border.frag.glsl | 13 +++++++++++++ yt_idv/shaders/passthrough.frag.glsl | 4 ---- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 yt_idv/shaders/display_border.frag.glsl diff --git a/yt_idv/scene_components/base_component.py b/yt_idv/scene_components/base_component.py index e968d37d..2422003c 100644 --- a/yt_idv/scene_components/base_component.py +++ b/yt_idv/scene_components/base_component.py @@ -228,7 +228,7 @@ def _final_pass_vertex_default(self): @traitlets.default("final_pass_fragment") def _final_pass_fragment_default(self): - return "passthrough" + return "display_border" @traitlets.default("base_quad") def _default_base_quad(self): diff --git a/yt_idv/shaders/display_border.frag.glsl b/yt_idv/shaders/display_border.frag.glsl new file mode 100644 index 00000000..e5c963b8 --- /dev/null +++ b/yt_idv/shaders/display_border.frag.glsl @@ -0,0 +1,13 @@ +in vec2 UV; + +out vec4 color; + +void main(){ + color = texture(fb_tex, UV); + color.a = 1.0; + vec2 d = abs(UV - vec2(0.5)); + if(0.5 - max(d.x, d.y) < draw_boundary) { + color = vec4(1.0, 1.0, 1.0, 0.5); + } + gl_FragDepth = texture(db_tex, UV).r; +} diff --git a/yt_idv/shaders/passthrough.frag.glsl b/yt_idv/shaders/passthrough.frag.glsl index e5c963b8..63b0d77d 100644 --- a/yt_idv/shaders/passthrough.frag.glsl +++ b/yt_idv/shaders/passthrough.frag.glsl @@ -5,9 +5,5 @@ out vec4 color; void main(){ color = texture(fb_tex, UV); color.a = 1.0; - vec2 d = abs(UV - vec2(0.5)); - if(0.5 - max(d.x, d.y) < draw_boundary) { - color = vec4(1.0, 1.0, 1.0, 0.5); - } gl_FragDepth = texture(db_tex, UV).r; } From 277cec6a6157cd61f6a8167045492fde5c8a4bb6 Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Sun, 30 Jun 2024 13:21:10 -0500 Subject: [PATCH 4/6] Add boundary colors, and reformat yaml --- yt_idv/scene_components/base_component.py | 14 +- yt_idv/shaders/display_border.frag.glsl | 2 +- yt_idv/shaders/known_uniforms.inc.glsl | 1 + yt_idv/shaders/shaderlist.yaml | 151 ++++++++++++---------- 4 files changed, 96 insertions(+), 72 deletions(-) diff --git a/yt_idv/scene_components/base_component.py b/yt_idv/scene_components/base_component.py index 2422003c..9f2eeea7 100644 --- a/yt_idv/scene_components/base_component.py +++ b/yt_idv/scene_components/base_component.py @@ -59,17 +59,20 @@ class SceneComponent(traitlets.HasTraits): display_name = traitlets.Unicode(allow_none=True) - final_pass_vertex = ShaderTrait(allow_none=True).tag(shader_type="fragment") - final_pass_fragment = ShaderTrait(allow_none=True).tag(shader_type="vertex") + final_pass_vertex = ShaderTrait(allow_none=True).tag(shader_type="vertex") + final_pass_fragment = ShaderTrait(allow_none=True).tag(shader_type="fragment") _final_pass = traitlets.Instance(ShaderProgram, allow_none=True) _final_pass_invalid = True - # These attributes are + # These attributes are just for colormap application cmap_min = traitlets.CFloat(None, allow_none=True) cmap_max = traitlets.CFloat(None, allow_none=True) cmap_log = traitlets.Bool(True) scale = traitlets.CFloat(1.0) + # This attribute determines whether or not this component is "active" + active = traitlets.Bool(True) + @traitlets.observe("display_bounds") def _change_display_bounds(self, change): # We need to update the framebuffer if the width or height has changed @@ -333,6 +336,11 @@ def run_program(self, scene): if draw_boundary > 0.0: with self.final_pass.enable() as p3: p3._set_uniform("draw_boundary", float(draw_boundary)) + if self.active: + boundary_color = np.array([0.0, 0.0, 1.0, 1.0], dtype="float32") + else: + boundary_color = np.array([0.5, 0.5, 0.5, 1.0], dtype="float32") + p3._set_uniform("boundary_color", boundary_color) with self.base_quad.vertex_array.bind(p3): GL.glViewport(x0, y0, w, h) GL.glDrawArrays(GL.GL_TRIANGLES, 0, 6) diff --git a/yt_idv/shaders/display_border.frag.glsl b/yt_idv/shaders/display_border.frag.glsl index e5c963b8..1e5670c7 100644 --- a/yt_idv/shaders/display_border.frag.glsl +++ b/yt_idv/shaders/display_border.frag.glsl @@ -7,7 +7,7 @@ void main(){ color.a = 1.0; vec2 d = abs(UV - vec2(0.5)); if(0.5 - max(d.x, d.y) < draw_boundary) { - color = vec4(1.0, 1.0, 1.0, 0.5); + color = vec4(boundary_color); } gl_FragDepth = texture(db_tex, UV).r; } diff --git a/yt_idv/shaders/known_uniforms.inc.glsl b/yt_idv/shaders/known_uniforms.inc.glsl index 4f2cb991..9073e1af 100644 --- a/yt_idv/shaders/known_uniforms.inc.glsl +++ b/yt_idv/shaders/known_uniforms.inc.glsl @@ -65,3 +65,4 @@ uniform float iso_alphas[32]; // draw outline control uniform float draw_boundary; +uniform vec4 boundary_color; diff --git a/yt_idv/shaders/shaderlist.yaml b/yt_idv/shaders/shaderlist.yaml index 91a12820..4b91943a 100644 --- a/yt_idv/shaders/shaderlist.yaml +++ b/yt_idv/shaders/shaderlist.yaml @@ -4,138 +4,153 @@ shader_definitions: info: A constant value applied source: constant.frag.glsl blend_func: - - one - - one + - one + - one blend_equation: func add constant_rgba: - info: A constant, specified RGBa value applied - source: constant_rgba.frag.glsl - blend_func: - - one - - one - blend_equation: func add + info: A constant, specified RGBa value applied + source: constant_rgba.frag.glsl + blend_func: + - one + - one + blend_equation: func add apply_colormap: - info: A second pass fragment shader used to apply a colormap to the result of + info: + A second pass fragment shader used to apply a colormap to the result of the first pass rendering source: apply_colormap.frag.glsl blend_func: - - src alpha - - dst alpha + - src alpha + - dst alpha blend_equation: func add expand_1d: info: This expands a 1D texture along the y dimension source: expand_1d.frag.glsl blend_func: - - one - - zero + - one + - zero blend_equation: func add draw_blocks: - info: A first pass fragment shader that performs ray casting using transfer function. + info: + A first pass fragment shader that performs ray casting using transfer function. See :ref:`volume-rendering-method` for more details. source: block_outline.frag.glsl blend_func: - - src alpha - - one minus src alpha + - src alpha + - one minus src alpha blend_equation: func add isocontour: info: A first pass fragment shader that renders isocontour layers. source: isocontour.frag.glsl blend_func: - - src alpha - - one minus src alpha + - src alpha + - one minus src alpha blend_equation: func add max_intensity: - info: A first pass fragment shader that computes Maximum Intensity Projection + info: + A first pass fragment shader that computes Maximum Intensity Projection of the data. See :ref:`projection-types` for more information. source: - - ray_tracing.frag.glsl - - max_intensity.frag.glsl + - ray_tracing.frag.glsl + - max_intensity.frag.glsl blend_func: - - one - - one + - one + - one blend_equation: max mesh: info: A vertex shader used for unstructured mesh rendering. source: mesh.frag.glsl depth_test: less blend_func: - - one - - zero + - one + - zero blend_equation: func add noop: - info: A second pass fragment shader that performs no operation. Usually used + info: + A second pass fragment shader that performs no operation. Usually used if the first pass already took care of applying proper color to the data source: noop.frag.glsl passthrough: - info: A first pass fragment shader that performs no operation. Used for debug + info: + A first pass fragment shader that performs no operation. Used for debug puproses. It's distinct from NoOpFragmentShader, because of the number of uniforms source: passthrough.frag.glsl blend_func: - - src alpha - - dst alpha + - src alpha + - dst alpha + blend_equation: func add + display_border: + info: Draws a border around the display area + source: display_border.frag.glsl + blend_func: + - src alpha + - dst alpha blend_equation: func add draw_lines: info: A line drawing fragment shader source: draw_lines.frag.glsl blend_func: - - one - - zero + - one + - zero blend_equation: func add projection: - info: A first pass fragment shader that performs unweighted integration of the + info: + A first pass fragment shader that performs unweighted integration of the data along the line of sight. See :ref:`projection-types` for more information. source: - - ray_tracing.frag.glsl - - projection.frag.glsl + - ray_tracing.frag.glsl + - projection.frag.glsl blend_func: - - one - - one + - one + - one blend_equation: func add text_overlay: info: A simple text overlay shader source: textoverlay.frag.glsl blend_func: - - src alpha - - one minus src alpha + - src alpha + - one minus src alpha blend_equation: func add transfer_function: - info: A first pass fragment shader that performs ray casting using transfer function. + info: + A first pass fragment shader that performs ray casting using transfer function. See :ref:`volume-rendering-method` for more details. source: - - ray_tracing.frag.glsl - - transfer_function.frag.glsl + - ray_tracing.frag.glsl + - transfer_function.frag.glsl blend_func_separate: - - one minus dst alpha - - one - - one minus dst alpha - - one + - one minus dst alpha + - one + - one minus dst alpha + - one blend_equation_separate: - - func add - - func add + - func add + - func add sph_kernel: info: Sample pre-integrated SPH kernel source: sph_kernel.frag.glsl blend_func: - - one - - one + - one + - one blend_equation: func add field_value: info: Use field values as input source: field_value.frag.glsl blend_func: - - one - - one + - one + - one slice_sample: info: Slice through a block collection source: slice_sample.frag.glsl depth_test: less blend_func: - - one - - zero + - one + - zero blend_equation: func add vertex: default: - info: A first pass vertex shader that tranlates the location of vertices from + info: + A first pass vertex shader that tranlates the location of vertices from the world coordinates to the viewing plane coordinates source: default.vert.glsl mesh: @@ -169,21 +184,21 @@ shader_definitions: source: particle_expand.geom.glsl component_shaders: curve_rendering: - default_value: default - default: - description: Default - first_vertex: mesh - first_fragment: constant_rgba - second_vertex: passthrough - second_fragment: passthrough + default_value: default + default: + description: Default + first_vertex: mesh + first_fragment: constant_rgba + second_vertex: passthrough + second_fragment: passthrough multi_curve_rendering: - default_value: default - default: - description: Default - first_vertex: mesh - first_fragment: constant_rgba - second_vertex: passthrough - second_fragment: passthrough + default_value: default + default: + description: Default + first_vertex: mesh + first_fragment: constant_rgba + second_vertex: passthrough + second_fragment: passthrough block_rendering: default_value: max_intensity max_intensity: From fd8cfd4069eda1a81323bf65a691cbc5c68d0e6e Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Fri, 5 Jul 2024 12:45:16 -0500 Subject: [PATCH 5/6] Minor c hange to try tracking the click status --- yt_idv/rendering_contexts/pyglet_context.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yt_idv/rendering_contexts/pyglet_context.py b/yt_idv/rendering_contexts/pyglet_context.py index 8eec5501..51b94a37 100644 --- a/yt_idv/rendering_contexts/pyglet_context.py +++ b/yt_idv/rendering_contexts/pyglet_context.py @@ -107,6 +107,11 @@ def center_window(self): self.set_position(0.5, 0.5) def on_mouse_press(self, x, y, button, modifiers): + self._currently_clicked = True + self._do_update = True + + def on_mouse_release(self, x, y, button, modifiers): + self._currently_clicked = False self._do_update = True def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): From f7f9de79a9053ce0a955132a7bae4b026885db27 Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Thu, 5 Dec 2024 12:19:48 -0600 Subject: [PATCH 6/6] Add example script --- examples/multiview_rendering.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 examples/multiview_rendering.py diff --git a/examples/multiview_rendering.py b/examples/multiview_rendering.py new file mode 100644 index 00000000..8e17d260 --- /dev/null +++ b/examples/multiview_rendering.py @@ -0,0 +1,23 @@ +import yt + +import yt_idv +from yt_idv.scene_components.particles import ParticleRendering +from yt_idv.scene_data.particle_positions import ParticlePositions + +ds = yt.load_sample("IsolatedGalaxy") + +rc = yt_idv.render_context(height=800, width=800, gui=True) +sg = rc.add_scene(ds, "density", no_ghost=True) + +sg.components[0].display_bounds = (0.0, 0.5, 0.0, 1.0) + +dd = ds.all_data() +pos = ParticlePositions(data_source=dd) +pren = ParticleRendering(data=pos) + +pren.display_bounds = (0.5, 1.0, 0.0, 1.0) + +sg.data_objects.append(pos) +sg.components.append(pren) + +rc.run()