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.
This commit is contained in:
Clément Foucault 2018-11-07 13:22:22 +01:00
parent faecd16d31
commit 84ad9b102e
6 changed files with 132 additions and 33 deletions

View File

@ -596,9 +596,11 @@ class PHYSICS_PT_smoke_viewport_display(PhysicButtonsPanel, Panel):
sub.prop(domain, "slice_axis")
sub.prop(domain, "slice_depth")
col = col.row()
col.enabled = do_full_slicing or not do_axis_slicing
col.prop(domain, "slice_per_voxel")
row = col.row()
row.enabled = do_full_slicing or not do_axis_slicing
row.prop(domain, "slice_per_voxel")
col.prop(domain, "display_interpolation")
class PHYSICS_PT_smoke_viewport_display_color(PhysicButtonsPanel, Panel):

View File

@ -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;

View File

@ -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)));

View File

@ -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[];
static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
{
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,
defines);
MEM_freeN(defines);
}
return e_data.volume_sh[id];
}
void workbench_volume_engine_init(void)
{
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(
datatoc_workbench_volume_vert_glsl, NULL,
datatoc_workbench_volume_frag_glsl,
"#define VOLUME_SLICE\n"
"#define USE_COBA\n");
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);

View File

@ -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;

View File

@ -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");