diff options
author | Sriharsha Kotcharlakot <k.venkatsriharsha@gmail.com> | 2020-09-15 18:51:14 +0300 |
---|---|---|
committer | Sriharsha Kotcharlakot <k.venkatsriharsha@gmail.com> | 2020-09-15 20:43:01 +0300 |
commit | f137022f9919f4dd315ec6b325a08e1bf5aec6fb (patch) | |
tree | 4b15aa230eb100e77b41dfffb8ef5e7501c55db5 /source/blender/draw/engines/workbench | |
parent | bedbd8655ed1d331aeaf756874c46dbed93168a1 (diff) |
Liquid Simulation Display Options (GSoC 2020)
All the changes made in the branch `soc-2020-fluid-tools` are included in this patch.
**Major changes:**
=== Viewport Display ===
- //Raw voxel display// or //closest (nearest-neighbor)// interpolation for displaying the underlying voxel data of the simulation grids more clearly.
- An option to display //gridlines// when the slicing method is //single//.
==== Grid Display ====
- Visualization for flags, pressure and level-set representation grids with a fixed color coding based on Manta GUI.
==== Vector Display ====
- //**M**arker **A**nd **C**ell// grid visualization options for vector grids like velocity or external forces.
- Made vector display options available for external forces.
==== Coloring options for //gridlines// ====
- Range highlighting and cell filtering options for displaying the simulation grid data more precisely.
- Color gridlines with flags.
- Also, made slicing and interpolation options available for Volume Object.
Reviewed By: JacquesLucke, sebbas
Differential Revision: https://developer.blender.org/D8705
Diffstat (limited to 'source/blender/draw/engines/workbench')
5 files changed, 222 insertions, 48 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index aa938d80fa3..eaa553a10de 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -10,6 +10,7 @@ uniform sampler2D depthBuffer; uniform sampler3D densityTexture; uniform sampler3D shadowTexture; uniform sampler3D flameTexture; +uniform usampler3D flagTexture; uniform sampler1D flameColorTexture; uniform sampler1D transferTexture; uniform mat4 volumeObjectToTexture; @@ -18,11 +19,16 @@ uniform int samplesLen = 256; uniform float noiseOfs = 0.0; uniform float stepLength; /* Step length in local space. */ uniform float densityScale; /* Simple Opacity multiplicator. */ +uniform float gridScale; /* Multiplicator for grid scaling. */ uniform vec3 activeColor; uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ +uniform bool showPhi = false; +uniform bool showFlags = false; +uniform bool showPressure = false; + #ifdef VOLUME_SLICE in vec3 localPos; #endif @@ -91,18 +97,89 @@ vec4 sample_tricubic(sampler3D ima, vec3 co) return color; } +/* Nearest-neighbor interpolation */ +vec4 sample_closest(sampler3D ima, vec3 co) +{ + /* Unnormalize coordinates */ + ivec3 cell_co = ivec3(co * vec3(textureSize(ima, 0).xyz)); + + return texelFetch(ima, cell_co, 0); +} + +vec4 flag_to_color(uint flag) +{ + /* Color mapping for flags */ + vec4 color = vec4(0.0, 0.0, 0.0, 0.06); + /* Cell types: 1 is Fluid, 2 is Obstacle, 4 is Empty, 8 is Inflow, 16 is Outflow */ + if (bool(flag & uint(1))) { + color.rgb += vec3(0.0, 0.0, 0.75); /* blue */ + } + if (bool(flag & uint(2))) { + color.rgb += vec3(0.2, 0.2, 0.2); /* dark gray */ + } + if (bool(flag & uint(4))) { + color.rgb += vec3(0.25, 0.0, 0.2); /* dark purple */ + } + if (bool(flag & uint(8))) { + color.rgb += vec3(0.0, 0.5, 0.0); /* dark green */ + } + if (bool(flag & uint(16))) { + color.rgb += vec3(0.9, 0.3, 0.0); /* orange */ + } + if (color.rgb == vec3(0.0)) { + color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */ + } + return color; +} + #ifdef USE_TRICUBIC # define sample_volume_texture sample_tricubic -#else +#elif defined(USE_TRILINEAR) # define sample_volume_texture sample_trilinear +#elif defined(USE_CLOSEST) +# define sample_volume_texture sample_closest #endif void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) { vec3 co = ls_pos * 0.5 + 0.5; #ifdef USE_COBA - float val = sample_volume_texture(densityTexture, co).r; - vec4 tval = texture(transferTexture, val) * densityScale; + vec4 tval; + if (showPhi) { + /* Color mapping for level-set representation */ + float val = sample_volume_texture(densityTexture, co).r * gridScale; + + val = max(min(val * 0.2, 1.0), -1.0); + + if (val >= 0.0) { + tval = vec4(val, 0.0, 0.5, 0.06); + } + else { + tval = vec4(0.5, 1.0 + val, 0.0, 0.06); + } + } + else if (showFlags) { + /* Color mapping for flags */ + uint flag = texture(flagTexture, co).r; + tval = flag_to_color(flag); + } + else if (showPressure) { + /* Color mapping for pressure */ + float val = sample_volume_texture(densityTexture, co).r * gridScale; + + if (val > 0) { + tval = vec4(val, val, val, 0.06); + } + else { + tval = vec4(-val, 0.0, 0.0, 0.06); + } + } + else { + float val = sample_volume_texture(densityTexture, co).r * gridScale; + tval = texture(transferTexture, val); + } + tval *= densityScale; + tval.rgb = pow(tval.rgb, vec3(2.2)); scattering = tval.rgb * 1500.0; extinction = max(1e-4, tval.a * 50.0); #else diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 80a8f310191..ed9cb17ae28 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -367,9 +367,11 @@ void workbench_cache_populate(void *ved, Object *ob) ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (md && BKE_modifier_is_enabled(wpd->scene, md, eModifierMode_Realtime)) { FluidModifierData *fmd = (FluidModifierData *)md; - if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { + if (fmd->domain) { workbench_volume_cache_populate(vedata, wpd->scene, ob, md, V3D_SHADING_SINGLE_COLOR); - return; /* Do not draw solid in this case. */ + if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { + return; /* Do not draw solid in this case. */ + } } } } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index d377f09ac73..81793367768 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -82,6 +82,13 @@ typedef enum eWORKBENCH_DataType { WORKBENCH_DATATYPE_MAX, } eWORKBENCH_DataType; +/* Types of volume display interpolation. */ +typedef enum eWORKBENCH_VolumeInterpType { + WORKBENCH_VOLUME_INTERP_LINEAR = 0, + WORKBENCH_VOLUME_INTERP_CUBIC, + WORKBENCH_VOLUME_INTERP_CLOSEST, +} eWORKBENCH_VolumeInterpType; + typedef struct WORKBENCH_FramebufferList { struct GPUFrameBuffer *opaque_fb; struct GPUFrameBuffer *opaque_infront_fb; @@ -428,7 +435,10 @@ GPUShader *workbench_shader_outline_get(void); GPUShader *workbench_shader_antialiasing_accumulation_get(void); GPUShader *workbench_shader_antialiasing_get(int stage); -GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic, bool smoke); +GPUShader *workbench_shader_volume_get(bool slice, + bool coba, + eWORKBENCH_VolumeInterpType interp_type, + bool smoke); void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, GPUShader **downsample_sh, diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c index af3b5d31b2b..b3b9e11ae58 100644 --- a/source/blender/draw/engines/workbench/workbench_shader.c +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -111,7 +111,7 @@ static struct { struct GPUShader *aa_accum_sh; struct GPUShader *smaa_sh[3]; - struct GPUShader *volume_sh[2][2][2][2]; + struct GPUShader *volume_sh[2][2][3][2]; struct DRWShaderLibrary *lib; } e_data = {{{{NULL}}}}; @@ -463,9 +463,12 @@ GPUShader *workbench_shader_antialiasing_get(int stage) return e_data.smaa_sh[stage]; } -GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic, bool smoke) +GPUShader *workbench_shader_volume_get(bool slice, + bool coba, + eWORKBENCH_VolumeInterpType interp_type, + bool smoke) { - GPUShader **shader = &e_data.volume_sh[slice][coba][cubic][smoke]; + GPUShader **shader = &e_data.volume_sh[slice][coba][interp_type][smoke]; if (*shader == NULL) { DynStr *ds = BLI_dynstr_new(); @@ -476,8 +479,16 @@ GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic, bool s if (coba) { BLI_dynstr_append(ds, "#define USE_COBA\n"); } - if (cubic) { - BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); + switch (interp_type) { + case WORKBENCH_VOLUME_INTERP_LINEAR: + BLI_dynstr_append(ds, "#define USE_TRILINEAR\n"); + break; + case WORKBENCH_VOLUME_INTERP_CUBIC: + BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); + break; + case WORKBENCH_VOLUME_INTERP_CLOSEST: + BLI_dynstr_append(ds, "#define USE_CLOSEST\n"); + break; } if (smoke) { BLI_dynstr_append(ds, "#define VOLUME_SMOKE\n"); diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index 7aa089d440f..c76f4a4c470 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -45,8 +45,10 @@ void workbench_volume_engine_init(WORKBENCH_Data *vedata) if (txl->dummy_volume_tx == NULL) { const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - txl->dummy_volume_tx = GPU_texture_create_3d("dummy_volume", 1, 1, 1, 1, GPU_RGBA8, zero); - txl->dummy_shadow_tx = GPU_texture_create_3d("dummy_shadow", 1, 1, 1, 1, GPU_RGBA8, one); + txl->dummy_volume_tx = GPU_texture_create_3d( + "dummy_volume", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, zero); + txl->dummy_shadow_tx = GPU_texture_create_3d( + "dummy_shadow", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, one); txl->dummy_coba_tx = GPU_texture_create_1d("dummy_coba", 1, 1, GPU_RGBA8, zero); } } @@ -70,8 +72,7 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata, DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DRWShadingGroup *grp = NULL; - /* Don't try to show liquid domains here */ - if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) { + if (!fds->fluid) { return; } @@ -79,19 +80,41 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata, if (fds->use_coba) { DRW_smoke_ensure_coba_field(fmd); } - else { + else if (fds->type == FLUID_DOMAIN_TYPE_GAS) { DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); } + else { + return; + } if ((!fds->use_coba && (fds->tex_density == NULL && fds->tex_color == NULL)) || (fds->use_coba && fds->tex_field == NULL)) { return; } - const bool use_slice = (fds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED && - fds->axis_slice_method == AXIS_SLICE_SINGLE); - const bool cubic_interp = (fds->interp_method == VOLUME_INTERP_CUBIC); - GPUShader *sh = workbench_shader_volume_get(use_slice, fds->use_coba, cubic_interp, true); + const bool use_slice = (fds->axis_slice_method == AXIS_SLICE_SINGLE); + const bool show_phi = ELEM(fds->coba_field, + FLUID_DOMAIN_FIELD_PHI, + FLUID_DOMAIN_FIELD_PHI_IN, + FLUID_DOMAIN_FIELD_PHI_OUT, + FLUID_DOMAIN_FIELD_PHI_OBSTACLE); + const bool show_flags = (fds->coba_field == FLUID_DOMAIN_FIELD_FLAGS); + const bool show_pressure = (fds->coba_field == FLUID_DOMAIN_FIELD_PRESSURE); + eWORKBENCH_VolumeInterpType interp_type = WORKBENCH_VOLUME_INTERP_LINEAR; + + switch ((FLUID_DisplayInterpolationMethod)fds->interp_method) { + case FLUID_DISPLAY_INTERP_LINEAR: + interp_type = WORKBENCH_VOLUME_INTERP_LINEAR; + break; + case FLUID_DISPLAY_INTERP_CUBIC: + interp_type = WORKBENCH_VOLUME_INTERP_CUBIC; + break; + case FLUID_DISPLAY_INTERP_CLOSEST: + interp_type = WORKBENCH_VOLUME_INTERP_CLOSEST; + break; + } + + GPUShader *sh = workbench_shader_volume_get(use_slice, fds->use_coba, interp_type, true); if (use_slice) { float invviewmat[4][4]; @@ -106,6 +129,7 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata, float step_length = max_ff(1e-16f, dim[axis] * 0.05f); grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis); DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); @@ -132,8 +156,19 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata, } if (fds->use_coba) { - DRW_shgroup_uniform_texture(grp, "densityTexture", fds->tex_field); - DRW_shgroup_uniform_texture(grp, "transferTexture", fds->tex_coba); + if (show_flags) { + DRW_shgroup_uniform_texture(grp, "flagTexture", fds->tex_field); + } + else { + DRW_shgroup_uniform_texture(grp, "densityTexture", fds->tex_field); + } + if (!show_phi && !show_flags && !show_pressure) { + DRW_shgroup_uniform_texture(grp, "transferTexture", fds->tex_coba); + } + DRW_shgroup_uniform_float_copy(grp, "gridScale", fds->grid_scale); + DRW_shgroup_uniform_bool_copy(grp, "showPhi", show_phi); + DRW_shgroup_uniform_bool_copy(grp, "showFlags", show_flags); + DRW_shgroup_uniform_bool_copy(grp, "showPressure", show_pressure); } else { static float white[3] = {1.0f, 1.0f, 1.0f}; @@ -192,11 +227,26 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, WORKBENCH_PrivateData *wpd = vedata->stl->wpd; WORKBENCH_TextureList *txl = vedata->txl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRWShadingGroup *grp = NULL; wpd->volumes_do = true; + const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE); + eWORKBENCH_VolumeInterpType interp_type = WORKBENCH_VOLUME_INTERP_LINEAR; + + switch ((VolumeDisplayInterpMethod)volume->display.interpolation_method) { + case VOLUME_DISPLAY_INTERP_LINEAR: + interp_type = WORKBENCH_VOLUME_INTERP_LINEAR; + break; + case VOLUME_DISPLAY_INTERP_CUBIC: + interp_type = WORKBENCH_VOLUME_INTERP_CUBIC; + break; + case VOLUME_DISPLAY_INTERP_CLOSEST: + interp_type = WORKBENCH_VOLUME_INTERP_CLOSEST; + break; + } /* Create shader. */ - GPUShader *sh = workbench_shader_volume_get(false, false, false, false); + GPUShader *sh = workbench_shader_volume_get(use_slice, false, interp_type, false); /* Compute color. */ float color[3]; @@ -206,36 +256,60 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, float texture_to_world[4][4]; mul_m4_m4m4(texture_to_world, ob->obmat, grid->texture_to_object); - /* Compute world space dimensions for step size. */ - float world_size[3]; - mat4_to_size(world_size, texture_to_world); - abs_v3(world_size); - - /* Compute step parameters. */ - double noise_ofs; - BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs); - float step_length, max_slice; - int resolution[3]; - GPU_texture_get_mipmap_size(grid->texture, 0, resolution); - float slice_ct[3] = {resolution[0], resolution[1], resolution[2]}; - mul_v3_fl(slice_ct, max_ff(0.001f, 5.0f)); - max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]); - invert_v3(slice_ct); - mul_v3_v3(slice_ct, world_size); - step_length = len_v3(slice_ct); + if (use_slice) { + float invviewmat[4][4]; + DRW_view_viewmat_get(NULL, invviewmat, true); + + const int axis = (volume->display.slice_axis == SLICE_AXIS_AUTO) ? + axis_dominant_v3_single(invviewmat[2]) : + volume->display.slice_axis - 1; + + float dim[3]; + BKE_object_dimensions_get(ob, dim); + /* 0.05f to achieve somewhat the same opacity as the full view. */ + float step_length = max_ff(1e-16f, dim[axis] * 0.05f); + + const float slice_position = volume->display.slice_depth; + + grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_float_copy(grp, "slicePosition", slice_position); + DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis); + DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); + DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT); + } + else { + /* Compute world space dimensions for step size. */ + float world_size[3]; + mat4_to_size(world_size, texture_to_world); + abs_v3(world_size); + + /* Compute step parameters. */ + double noise_ofs; + BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs); + float step_length, max_slice; + int resolution[3]; + GPU_texture_get_mipmap_size(grid->texture, 0, resolution); + float slice_ct[3] = {resolution[0], resolution[1], resolution[2]}; + mul_v3_fl(slice_ct, max_ff(0.001f, 5.0f)); + max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]); + invert_v3(slice_ct); + mul_v3_v3(slice_ct, world_size); + step_length = len_v3(slice_ct); + + /* Set uniforms. */ + grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice); + DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); + DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs); + DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); + } /* Compute density scale. */ const float density_scale = volume->display.density * BKE_volume_density_scale(volume, ob->obmat); - /* Set uniforms. */ - DRWShadingGroup *grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice); - DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); - DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs); - DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); - DRW_shgroup_uniform_texture(grp, "densityTexture", grid->texture); /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ DRW_shgroup_uniform_texture(grp, "shadowTexture", txl->dummy_shadow_tx); |