diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-11-07 15:22:22 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-11-07 15:25:28 +0300 |
commit | 84ad9b102e708da54188752bde34daba8b6611b2 (patch) | |
tree | 63a79d141fe9b934ae33d86d25a148e817b04272 /source | |
parent | faecd16d3168981b5af95be613e5a91de5c28133 (diff) |
Workbench: Add cubic filtering for smoke simulation
The option is per domain and only affects the solid / xray / wireframe view.
Eevee is not yet supported.
Diffstat (limited to 'source')
5 files changed, 125 insertions, 28 deletions
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index be3a025a96f..ced6cf0fe74 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -670,6 +670,7 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie tsds->slice_per_voxel = sds->slice_per_voxel; tsds->slice_depth = sds->slice_depth; tsds->slice_axis = sds->slice_axis; + tsds->interp_method = sds->interp_method; tsds->draw_velocity = sds->draw_velocity; tsds->vector_draw_type = sds->vector_draw_type; tsds->vector_scale = sds->vector_scale; 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 023ebb8e111..f14078a71eb 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -67,20 +67,73 @@ float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection) return max_v3(furthestplane); } +#define sample_trilinear(ima, co) texture(ima, co) + +vec4 sample_tricubic(sampler3D ima, vec3 co) +{ + vec3 tex_size = vec3(textureSize(ima, 0).xyz); + + co *= tex_size; + /* texel center */ + vec3 tc = floor(co - 0.5) + 0.5; + vec3 f = co - tc; + vec3 f2 = f * f; + vec3 f3 = f2 * f; + /* Bspline coefs (optimized) */ + vec3 w3 = f3 / 6.0; + vec3 w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; + vec3 w1 = f3 * 0.5 - f2 + 2.0 / 3.0; + vec3 w2 = 1.0 - w0 - w1 - w3; + + vec3 s0 = w0 + w1; + vec3 s1 = w2 + w3; + + vec3 f0 = w1 / (w0 + w1); + vec3 f1 = w3 / (w2 + w3); + + vec2 final_z; + vec4 final_co; + final_co.xy = tc.xy - 1.0 + f0.xy; + final_co.zw = tc.xy + 1.0 + f1.xy; + final_z = tc.zz + vec2(-1.0, 1.0) + vec2(f0.z, f1.z); + + final_co /= tex_size.xyxy; + final_z /= tex_size.zz; + + vec4 color; + color = texture(ima, vec3(final_co.xy, final_z.x)) * s0.x * s0.y * s0.z; + color += texture(ima, vec3(final_co.zy, final_z.x)) * s1.x * s0.y * s0.z; + color += texture(ima, vec3(final_co.xw, final_z.x)) * s0.x * s1.y * s0.z; + color += texture(ima, vec3(final_co.zw, final_z.x)) * s1.x * s1.y * s0.z; + + color += texture(ima, vec3(final_co.xy, final_z.y)) * s0.x * s0.y * s1.z; + color += texture(ima, vec3(final_co.zy, final_z.y)) * s1.x * s0.y * s1.z; + color += texture(ima, vec3(final_co.xw, final_z.y)) * s0.x * s1.y * s1.z; + color += texture(ima, vec3(final_co.zw, final_z.y)) * s1.x * s1.y * s1.z; + + return color; +} + +#ifdef USE_TRICUBIC +# define sample_volume_texture sample_tricubic +#else +# define sample_volume_texture sample_trilinear +#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 = texture(densityTexture, co).r; + float val = sample_volume_texture(densityTexture, co).r; vec4 tval = texture(transferTexture, val) * densityScale; tval.rgb = pow(tval.rgb, vec3(2.2)); scattering = tval.rgb * 1500.0; extinction = max(1e-4, tval.a * 50.0); #else - float flame = texture(flameTexture, co).r; + float flame = sample_volume_texture(flameTexture, co).r; vec4 emission = texture(flameColorTexture, flame); - float shadows = texture(shadowTexture, co).r; - vec4 density = texture(densityTexture, co); /* rgb: color, a: density */ + float shadows = sample_volume_texture(shadowTexture, co).r; + vec4 density = sample_volume_texture(densityTexture, co); /* rgb: color, a: density */ scattering = density.rgb * density.a * densityScale; extinction = max(1e-4, dot(scattering, vec3(0.33333))); diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index 0f6b3e5954a..e720bb6aa64 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -28,6 +28,7 @@ #include "BKE_modifier.h" #include "BLI_rand.h" +#include "BLI_dynstr.h" #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" @@ -35,8 +36,16 @@ #include "GPU_draw.h" +enum { + VOLUME_SH_SLICE = 0, + VOLUME_SH_COBA, + VOLUME_SH_CUBIC, +}; + +#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1)) + static struct { - struct GPUShader *volume_sh; + struct GPUShader *volume_sh[VOLUME_SH_MAX]; struct GPUShader *volume_coba_sh; struct GPUShader *volume_slice_sh; struct GPUShader *volume_slice_coba_sh; @@ -47,26 +56,43 @@ static struct { extern char datatoc_workbench_volume_vert_glsl[]; extern char datatoc_workbench_volume_frag_glsl[]; -void workbench_volume_engine_init(void) +static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) { - if (!e_data.volume_sh) { - e_data.volume_sh = DRW_shader_create( - datatoc_workbench_volume_vert_glsl, NULL, - datatoc_workbench_volume_frag_glsl, NULL); - e_data.volume_coba_sh = DRW_shader_create( - datatoc_workbench_volume_vert_glsl, NULL, - datatoc_workbench_volume_frag_glsl, - "#define USE_COBA\n"); - e_data.volume_slice_sh = DRW_shader_create( - datatoc_workbench_volume_vert_glsl, NULL, - datatoc_workbench_volume_frag_glsl, - "#define VOLUME_SLICE\n"); - e_data.volume_slice_coba_sh = DRW_shader_create( + int id = 0; + id += (slice) ? (1 << VOLUME_SH_SLICE) : 0; + id += (coba) ? (1 << VOLUME_SH_COBA) : 0; + id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0; + + if (!e_data.volume_sh[id]) { + DynStr *ds = BLI_dynstr_new(); + + if (slice) { + BLI_dynstr_append(ds, "#define VOLUME_SLICE\n"); + } + if (coba) { + BLI_dynstr_append(ds, "#define USE_COBA\n"); + } + if (cubic) { + BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); + } + + char *defines = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + e_data.volume_sh[id] = DRW_shader_create( datatoc_workbench_volume_vert_glsl, NULL, datatoc_workbench_volume_frag_glsl, - "#define VOLUME_SLICE\n" - "#define USE_COBA\n"); + defines); + MEM_freeN(defines); + } + + return e_data.volume_sh[id]; +} + +void workbench_volume_engine_init(void) +{ + if (!e_data.dummy_tex) { float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f}; e_data.dummy_tex = GPU_texture_create_3D(1, 1, 1, GPU_RGBA8, pixel, NULL); e_data.dummy_coba_tex = GPU_texture_create_1D(1, GPU_RGBA8, pixel, NULL); @@ -75,10 +101,9 @@ void workbench_volume_engine_init(void) void workbench_volume_engine_free(void) { - DRW_SHADER_FREE_SAFE(e_data.volume_sh); - DRW_SHADER_FREE_SAFE(e_data.volume_coba_sh); - DRW_SHADER_FREE_SAFE(e_data.volume_slice_sh); - DRW_SHADER_FREE_SAFE(e_data.volume_slice_coba_sh); + for (int i = 0; i < VOLUME_SH_MAX; ++i) { + DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]); + } DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex); DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex); } @@ -121,6 +146,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec const bool use_slice = (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED && sds->axis_slice_method == AXIS_SLICE_SINGLE); + const bool cubic_interp = (sds->interp_method == VOLUME_INTERP_CUBIC); + GPUShader *sh = volume_shader_get(use_slice, sds->use_coba, cubic_interp); if (use_slice) { float invviewmat[4][4]; @@ -130,7 +157,6 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec ? axis_dominant_v3_single(invviewmat[2]) : sds->slice_axis - 1; - GPUShader *sh = (sds->use_coba) ? e_data.volume_slice_coba_sh : e_data.volume_slice_sh; grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis); @@ -140,7 +166,6 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec BLI_halton_1D(3, 0.0, effect_info->jitter_index, &noise_ofs); int max_slices = max_iii(sds->res[0], sds->res[1], sds->res[2]) * sds->slice_per_voxel; - GPUShader *sh = (sds->use_coba) ? e_data.volume_coba_sh : e_data.volume_sh; grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slices); diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index b8ac0de0090..97913e29ad4 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -72,6 +72,12 @@ enum { SLICE_AXIS_Z = 3, }; +/* axis aligned method */ +enum { + VOLUME_INTERP_LINEAR = 0, + VOLUME_INTERP_CUBIC = 1, +}; + enum { VECTOR_DRAW_NEEDLE = 0, VECTOR_DRAW_STREAMLINE = 1, @@ -222,7 +228,7 @@ typedef struct SmokeDomainSettings { char vector_draw_type; char use_coba; char coba_field; /* simulation field used for the color mapping */ - char pad2; + char interp_method; float clipping; float pad3; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 5eb25985fa4..591798d508a 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -514,6 +514,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static const EnumPropertyItem interp_method_item[] = { + {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"}, + {VOLUME_INTERP_CUBIC, "CUBIC", 0, "Cubic", "Smoothed high quality interpolation, but slower"}, + {0, NULL, 0, NULL, NULL} + }; + static const EnumPropertyItem axis_slice_position_items[] = { {SLICE_AXIS_AUTO, "AUTO", 0, "Auto", "Adjust slice direction according to the view direction"}, {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"}, @@ -856,6 +862,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "interp_method"); + RNA_def_property_enum_items(prop, interp_method_item); + RNA_def_property_ui_text(prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + prop = RNA_def_property(srna, "display_velocity", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0); RNA_def_property_ui_text(prop, "Display Velocity", "Toggle visualization of the velocity field as needles"); |