Skip to content

Commit

Permalink
added orthogonal slicing to volume renderer and to corresponding example
Browse files Browse the repository at this point in the history
  • Loading branch information
sgumhold committed Jan 17, 2024
1 parent 4f2e273 commit 71817c5
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 26 deletions.
63 changes: 45 additions & 18 deletions libs/cgv_gl/glsl/volume.glfs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ mat3 get_inverse_normal_matrix();
#define ISOSURFACE_MODE 0
#define ISOSURFACE_COLOR_MODE 0

// 0 - Disabled
// 1 - Opaque
// 2 - Transparent
#define SLICE_MODE 0

// automatic defines
#define TRANSFER_FUNCTION_SAMPLER_DIMENSIONS 1

Expand Down Expand Up @@ -77,12 +82,12 @@ layout (binding = 3) uniform sampler3D gradient_tex;
layout (binding = 4) uniform sampler2D depth_tex;
#endif

uniform vec2 viewport_dims;
uniform vec2 noise_offset;
uniform vec2 viewport_dims;
uniform vec2 noise_offset;
uniform float scale_adjustment_factor;

uniform bool light_local_to_eye;
uniform vec3 light_direction;
uniform bool light_local_to_eye;
uniform vec3 light_direction;
uniform float ambient_strength;
uniform float diffuse_strength;
uniform float specular_strength;
Expand All @@ -92,10 +97,14 @@ uniform float specular_color_mix;
uniform float gradient_lambda;

uniform float isovalue;
uniform vec3 isosurface_color;
uniform vec3 isosurface_color;

uniform int slice_axis;
uniform float slice_coordinate;
uniform float slice_opacity;

uniform vec3 clip_box_min;
uniform vec3 clip_box_max;
uniform vec3 clip_box_min;
uniform vec3 clip_box_max;

// in/out parameters
in vec3 position_object;
Expand Down Expand Up @@ -382,6 +391,9 @@ void main() {
// initial color with full transparency for front-to-back blending
vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
// step count (needed later for averaging the density if using average compositing mode)
#if SLICE_MODE > 0
bool initial_side_slice = mix(clip_box_min, clip_box_max, ray.origin)[slice_axis] > slice_coordinate;
#endif
int istep = 0;
for(istep; istep < NUM_STEPS; ++istep) {
float t = istep * step_size;
Expand Down Expand Up @@ -411,7 +423,6 @@ void main() {

// apply the transfer function
vec4 color_in = apply_transfer_function(density);

#if ISOSURFACE_MODE > 0
#if ISOSURFACE_MODE == 1
bool is_isosurface = density >= isovalue;
Expand Down Expand Up @@ -446,7 +457,6 @@ void main() {
#if ENABLE_GRADIENT_MODULATION == 1
opacity_modulation = pow(gradient_length, gradient_lambda);
#endif

#if ISOSURFACE_MODE > 0
if(is_isosurface) {
#if ISOSURFACE_COLOR_MODE == 0
Expand All @@ -463,22 +473,35 @@ void main() {
break;
}
#endif

#if SLICE_MODE > 0
bool at_slice = ((uvw[slice_axis] > slice_coordinate) != initial_side_slice);
if (at_slice) {
#if SLICE_MODE == 1
color_in.a = 1.0;
#else
color_in.a = slice_opacity;
#endif
initial_side_slice = !initial_side_slice;
}
else {
#endif
#if ENABLE_LIGHTING == 1
color_in.rgb = apply_lighting(color_in.rgb, illumination);
color_in.rgb = apply_lighting(color_in.rgb, illumination);
#endif

// apply opacity modulation as determined by gradient length if enabled
color_in.a *= opacity_modulation;
// apply opacity modulation as determined by gradient length if enabled
color_in.a *= opacity_modulation;

color_in.a = -exp(-step_size * scale_adjustment_factor * color_in.a) + 1.0;

color_in.a = -exp(-step_size * scale_adjustment_factor * color_in.a) + 1.0;
#if SLICE_MODE > 0
}
#endif
// premultiply alpha
color_in.rgb *= color_in.a;

// blend front-to-back
color.rgb = color.a*color_in.rgb + color.rgb;
color.a = (1.0 - color_in.a)*color.a;
color.rgb += color.a*color_in.rgb;
color.a *= (1.0 - color_in.a);

// early termination when transparency threshold is reached
#if ENABLE_ISOSURFACE == 0
Expand All @@ -487,7 +510,11 @@ void main() {
break;
}
#endif

#if SLICE_MODE == 1
if (at_slice) {
break;
}
#endif
#endif
}

Expand Down
20 changes: 20 additions & 0 deletions libs/cgv_gl/volume_renderer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ namespace cgv {
isosurface_color = rgb(0.7f);
isosurface_color_from_transfer_function = false;

slice_mode = SM_DISABLED;
slice_axis = 2;
slice_coordinate = 0.5f;
slice_opacity = 0.5f;

clip_box = box3(vec3(0.0f), vec3(1.0f));
}

Expand Down Expand Up @@ -114,6 +119,8 @@ namespace cgv {
shader_code::set_define(defines, "ISOSURFACE_MODE", vrs.isosurface_mode, volume_render_style::IM_NONE);
shader_code::set_define(defines, "ISOSURFACE_COLOR_MODE", vrs.isosurface_color_from_transfer_function, false);

shader_code::set_define(defines, "SLICE_MODE", vrs.slice_mode, volume_render_style::SM_DISABLED);

shader_code::set_define(defines, "COMPOSITING_MODE", vrs.compositing_mode, volume_render_style::CM_BLEND);
if(transfer_function_texture)
shader_code::set_define(defines, "TRANSFER_FUNCTION_SAMPLER_DIMENSIONS", transfer_function_texture->get_nr_dimensions(), 1u);
Expand Down Expand Up @@ -218,6 +225,10 @@ namespace cgv {
ref_prog().set_uniform(ctx, "isovalue", vrs.isovalue);
ref_prog().set_uniform(ctx, "isosurface_color", vrs.isosurface_color);

ref_prog().set_uniform(ctx, "slice_axis", vrs.slice_axis);
ref_prog().set_uniform(ctx, "slice_coordinate", vrs.slice_coordinate);
ref_prog().set_uniform(ctx, "slice_opacity", vrs.slice_opacity);

ref_prog().set_uniform(ctx, "clip_box_min", vrs.clip_box.get_min_pnt());
ref_prog().set_uniform(ctx, "clip_box_max", vrs.clip_box.get_max_pnt());

Expand Down Expand Up @@ -321,6 +332,15 @@ namespace cgv {
p->align("\b");
p->end_tree_node(vrs_ptr->enable_gradient_modulation);
}
if (p->begin_tree_node("Orthogonal Slicing", vrs_ptr->slice_mode, false)) {
p->align("\a");
p->add_member_control(b, "Mode", vrs_ptr->slice_mode, "dropdown", "enums='Disabled,Opaque,Transparent'");
p->add_member_control(b, "Axis", vrs_ptr->slice_axis, "value_slider", "min=0;max=2;ticks=true");
p->add_member_control(b, "Coordinate", vrs_ptr->slice_coordinate, "value_slider", "min=0;max=1;ticks=true");
p->add_member_control(b, "Opacity", vrs_ptr->slice_opacity, "value_slider", "min=0;max=1;ticks=true");
p->align("\b");
p->end_tree_node(vrs_ptr->slice_mode);
}

if(p->begin_tree_node("Isosurface (Blend only)", vrs_ptr->isosurface_mode, false)) {
p->align("\a");
Expand Down
13 changes: 13 additions & 0 deletions libs/cgv_gl/volume_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ namespace cgv { // @<
/// whether to color the isosurface based on the transfer function
bool isosurface_color_from_transfer_function;

/// mode of slice rendering
enum SliceMode {
SM_DISABLED = 0, // no slice
SM_OPAQUE = 1, // opaque slice rendering
SM_TRANSPARENT = 2 // transparent slice rendering
} slice_mode;
/// coordinate axis orthogonal to which slice is rendered
int slice_axis;
/// coordinate value along axis defining slice in range [0,1]
float slice_coordinate;
/// in case of transparent mode, slice opacity
float slice_opacity;

/// a bounding box used to define a subspace of the volume to be visualized
box3 clip_box;

Expand Down
31 changes: 25 additions & 6 deletions plugins/examples/volume_rendering.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace cgv {
}
}

volume_viewer::volume_viewer() : application_plugin("Volume Viewer")
volume_viewer::volume_viewer() : application_plugin("Volume Viewer"), depth_tex("[D]")
{
// setup volume bounding box as unit cube centered around origin
volume_bounding_box = box3(vec3(-0.5f), vec3(0.5f));
Expand All @@ -32,7 +32,11 @@ volume_viewer::volume_viewer() : application_plugin("Volume Viewer")
volume_tex.set_wrap_r(cgv::render::TW_CLAMP_TO_BORDER);
volume_tex.set_border_color(0.0f, 0.0f, 0.0f, 0.0f);

vstyle.enable_depth_test = false;
// an extra depth texture is used to enable mixing of opaque geometry and the volume
depth_tex.set_min_filter(cgv::render::TF_NEAREST);
depth_tex.set_mag_filter(cgv::render::TF_NEAREST);

vstyle.enable_depth_test = true;

show_box = true;

Expand Down Expand Up @@ -174,26 +178,41 @@ void volume_viewer::init_frame(cgv::render::context& ctx) {
transfer_function_legend_ptr->set_color_map(ctx, transfer_function);
}
}
if (depth_tex.is_created() && (ctx.get_width() != depth_tex.get_width() || ctx.get_height() != depth_tex.get_height()))
depth_tex.destruct(ctx);

if (!depth_tex.is_created())
depth_tex.create(ctx, cgv::render::TT_2D, ctx.get_width(), ctx.get_height());
}

void volume_viewer::draw(cgv::render::context& ctx)
void volume_viewer::draw(cgv::render::context& ctx)
{
// default render style for the bounding box
static const cgv::render::box_wire_render_style box_rs;

// render the wireframe bounding box if enabled
if(show_box)
if (show_box)
box_rd.render(ctx, cgv::render::ref_box_wire_renderer(ctx), box_rs);

}

void volume_viewer::after_finish(cgv::render::context & ctx)
{
if (!view_ptr)
return;

// copy the contents of the depth buffer from the opaque geometry into the extra depth texture
depth_tex.replace_from_buffer(ctx, 0, 0, 0, 0, ctx.get_width(), ctx.get_height());

// render the volume
auto& vr = cgv::render::ref_volume_renderer(ctx);
vr.set_render_style(vstyle);
vr.set_volume_texture(&volume_tex); // set volume texture as 3D scalar input data
vr.set_transfer_function_texture(&transfer_function.ref_texture()); // get the texture from the transfer function color map to transform scalar volume values into RGBA colors
// set the volume bounding box and enable transform to automatically place and size the volume to the defined bounds
vr.set_bounding_box(volume_bounding_box);
vr.set_depth_texture(&depth_tex);
vr.transform_to_bounding_box(true);

vr.render(ctx, 0, 0);
}

Expand Down Expand Up @@ -640,4 +659,4 @@ void volume_viewer::create_histogram() {

#include <cgv/base/register.h>

cgv::base::factory_registration<volume_viewer> volume_viewer_fac("New/Render/Volume Rendering");
cgv::base::factory_registration<volume_viewer> volume_viewer_fac("Volume Rendering", "shortcut='Ctrl-Alt-V';menu_text='New/Render/Volume Rendering'", true);
6 changes: 4 additions & 2 deletions plugins/examples/volume_rendering.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class volume_viewer :
cgv::app::color_map_editor_ptr transfer_function_editor_ptr;
cgv::app::color_map_legend_ptr transfer_function_legend_ptr;

/// resolution of the volume
/// resolution of the volume
uvec3 vres;
/// spacing of the voxels
vec3 vspacing;
Expand All @@ -36,7 +36,8 @@ class volume_viewer :
std::vector<float> vol_data;
box3 volume_bounding_box;
cgv::render::texture volume_tex;

cgv::render::texture depth_tex;


// Render members
/// store a pointer to the view
Expand Down Expand Up @@ -88,6 +89,7 @@ class volume_viewer :
bool init(cgv::render::context& ctx);
void init_frame(cgv::render::context& ctx);
void draw(cgv::render::context& ctx);
void after_finish(cgv::render::context& ctx);

// interface of provider
void create_gui();
Expand Down

0 comments on commit 71817c5

Please sign in to comment.