Skip to content

Commit

Permalink
Merge branch 'main' into sph_vol_render_working
Browse files Browse the repository at this point in the history
  • Loading branch information
chrishavlin authored Dec 9, 2024
2 parents b35e30e + e093d4e commit a150b07
Show file tree
Hide file tree
Showing 12 changed files with 359 additions and 62 deletions.
23 changes: 23 additions & 0 deletions examples/multiview_rendering.py
Original file line number Diff line number Diff line change
@@ -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()
1 change: 1 addition & 0 deletions yt_idv/cameras/base_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class BaseCamera(traitlets.HasTraits):
up = traittypes.Array(np.array([0.0, 0.0, 1.0])).valid(
ndarray_shape(3), ndarray_ro()
)
scroll_delta = traitlets.Float(0.1)
fov = traitlets.Float(45.0)
near_plane = traitlets.Float(0.001)
far_plane = traitlets.Float(20.0)
Expand Down
7 changes: 6 additions & 1 deletion yt_idv/rendering_contexts/pyglet_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -129,7 +134,7 @@ def on_mouse_scroll(self, x, y, scroll_x, scroll_y):

camera = self.scene.camera # current camera
dpos = (
0.1
camera.scroll_delta
* (camera.position - camera.focus)
/ np.linalg.norm(camera.position - camera.focus)
)
Expand Down
113 changes: 101 additions & 12 deletions yt_idv/scene_components/base_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)
from yt_idv.scene_data.base_data import SceneData
from yt_idv.shader_objects import (
PreprocessorDefinitionState,
ShaderProgram,
ShaderTrait,
component_shaders,
Expand Down Expand Up @@ -58,18 +59,28 @@ class SceneComponent(traitlets.HasTraits):
colormap = traitlets.Instance(ColormapTexture)
_program1 = traitlets.Instance(ShaderProgram, allow_none=True)
_program2 = traitlets.Instance(ShaderProgram, allow_none=True)
_program1_pp_defs = traitlets.Instance(PreprocessorDefinitionState, allow_none=True)
_program2_pp_defs = traitlets.Instance(PreprocessorDefinitionState, allow_none=True)
_program1_invalid = True
_program2_invalid = True
_cmap_bounds_invalid = True

display_name = traitlets.Unicode(allow_none=True)

# These attributes are
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 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
Expand Down Expand Up @@ -144,15 +155,38 @@ def _default_display_name(self):
def _default_render_method(self):
return default_shader_combos[self.name]

@traitlets.default("_program1_pp_defs")
def _default_program1_pp_defs(self):
return PreprocessorDefinitionState()

@traitlets.default("_program2_pp_defs")
def _default_program2_pp_defs(self):
return PreprocessorDefinitionState()

@traitlets.observe("render_method")
def _change_render_method(self, change):
new_combo = component_shaders[self.name][change["new"]]
with self.hold_trait_notifications():
self.vertex_shader = new_combo["first_vertex"]
self.fragment_shader = new_combo["first_fragment"]
self.geometry_shader = new_combo.get("first_geometry", None)
self.colormap_vertex = new_combo["second_vertex"]
self.colormap_fragment = new_combo["second_fragment"]
self.vertex_shader = (
new_combo["first_vertex"],
self._program1_pp_defs["vertex"],
)
self.fragment_shader = (
new_combo["first_fragment"],
self._program1_pp_defs["fragment"],
)
self.geometry_shader = (
new_combo.get("first_geometry", None),
self._program1_pp_defs["geometry"],
)
self.colormap_vertex = (
new_combo["second_vertex"],
self._program2_pp_defs["vertex"],
)
self.colormap_fragment = (
new_combo["second_fragment"],
self._program2_pp_defs["fragment"],
)

@traitlets.observe("render_method")
def _add_initial_isolayer(self, change):
Expand Down Expand Up @@ -191,10 +225,23 @@ def _change_colormap_fragment(self, change):
self._program2_invalid = True

@traitlets.observe("use_db")
def _initialize_db(self, changed):
# invaldiate the colormap when the depth buffer selection changes
def _toggle_depth_buffer(self, changed):
# invalidate the colormap when the depth buffer selection changes
self._cmap_bounds_invalid = True

# update the preprocessor state: USE_DB only present in the second
# program, only update that one.
if changed["new"]:
self._program2_pp_defs.add_definition("fragment", ("USE_DB", ""))
else:
self._program2_pp_defs.clear_definition("fragment", ("USE_DB", ""))

# update the colormap fragment with current render method
current_combo = component_shaders[self.name][self.render_method]
pp_defs = self._program2_pp_defs["fragment"]
self.colormap_fragment = current_combo["second_fragment"], pp_defs
self._recompile_shader()

@traitlets.default("colormap")
def _default_colormap(self):
cm = ColormapTexture()
Expand Down Expand Up @@ -222,6 +269,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 "display_border"

@traitlets.default("base_quad")
def _default_base_quad(self):
bq = SceneData(
Expand All @@ -241,7 +296,9 @@ def program1(self):
self._program1.delete_program()
self._fragment_shader_default()
self._program1 = ShaderProgram(
self.vertex_shader, self.fragment_shader, self.geometry_shader
self.vertex_shader,
self.fragment_shader,
self.geometry_shader,
)
self._program1_invalid = False
return self._program1
Expand All @@ -254,10 +311,23 @@ def program2(self):
# The vertex shader will always be the same.
# The fragment shader will change based on whether we are
# colormapping or not.
self._program2 = ShaderProgram(self.colormap_vertex, self.colormap_fragment)
self._program2 = ShaderProgram(
self.colormap_vertex,
self.colormap_fragment,
)
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)))
Expand All @@ -273,6 +343,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:
Expand All @@ -296,7 +370,6 @@ def run_program(self, scene):
p2._set_uniform("cmap", 0)
p2._set_uniform("fb_tex", 1)
p2._set_uniform("db_tex", 2)
p2._set_uniform("use_db", self.use_db)
# Note that we use cmap_min/cmap_max, not
# self.cmap_min/self.cmap_max.
p2._set_uniform("cmap_min", self.cmap_min)
Expand All @@ -308,6 +381,18 @@ 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))
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)

def draw(self, scene, program):
raise NotImplementedError

Expand Down Expand Up @@ -378,12 +463,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:
Expand Down
Loading

0 comments on commit a150b07

Please sign in to comment.