diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index 99aa54a958a..829850e4f2f 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -349,5 +349,40 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel): domain = context.smoke.domain_settings effector_weights_ui(self, context, domain.effector_weights, 'SMOKE') + +class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel): + bl_label = "Smoke Display Settings" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + md = context.smoke + rd = context.scene.render + return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine) + + def draw(self, context): + domain = context.smoke.domain_settings + layout = self.layout + + layout.prop(domain, "display_thickness") + + layout.separator() + layout.label(text="Slicing:") + layout.prop(domain, "slice_method") + + slice_method = domain.slice_method + axis_slice_method = domain.axis_slice_method + + if slice_method == 'AXIS_ALIGNED': + layout.prop(domain, "axis_slice_method") + + if axis_slice_method == 'SINGLE': + layout.prop(domain, "slice_axis") + layout.prop(domain, "slice_depth") + + if axis_slice_method == 'FULL': + layout.prop(domain, "slice_per_voxel") + + if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index f622d541f3a..d0f546e9bef 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -536,6 +536,13 @@ void smokeModifier_createType(struct SmokeModifierData *smd) #endif smd->domain->data_depth = 0; smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE; + + smd->domain->display_thickness = 1.0f; + smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED; + smd->domain->axis_slice_method = AXIS_SLICE_FULL; + smd->domain->slice_per_voxel = 5.0f; + smd->domain->slice_depth = 0.5f; + smd->domain->slice_axis = 0; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -629,6 +636,12 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData tsmd->domain->openvdb_comp = smd->domain->openvdb_comp; tsmd->domain->data_depth = smd->domain->data_depth; tsmd->domain->cache_file_format = smd->domain->cache_file_format; + + tsmd->domain->slice_method = smd->domain->slice_method; + tsmd->domain->axis_slice_method = smd->domain->axis_slice_method; + tsmd->domain->slice_per_voxel = smd->domain->slice_per_voxel; + tsmd->domain->slice_depth = smd->domain->slice_depth; + tsmd->domain->slice_axis = smd->domain->slice_axis; } else if (tsmd->flow) { tsmd->flow->psys = smd->flow->psys; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index aa5ef1c98cf..0d4ff00b775 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -52,6 +52,7 @@ #include "DNA_linestyle_types.h" #include "DNA_actuator_types.h" #include "DNA_view3d_types.h" +#include "DNA_smoke_types.h" #include "DNA_genfile.h" @@ -1405,5 +1406,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) scene->r.ffcodecdata.constant_rate_factor = FFM_CRF_NONE; } } + + if (!DNA_struct_elem_find(fd->filesdna, "SmokeModifierData", "float", "slice_per_voxel")) { + Object *ob; + ModifierData *md; + + for (ob = main->object.first; ob; ob = ob->id.next) { + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData *)md; + if (smd->domain) { + smd->domain->slice_per_voxel = 5.0f; + smd->domain->slice_depth = 0.5f; + smd->domain->display_thickness = 1.0f; + } + } + } + } + } } } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 06677ef4476..d743e7c09e7 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -113,6 +113,63 @@ typedef struct VolumeSlicer { float (*verts)[3]; } VolumeSlicer; +/* *************************** Axis Aligned Slicing ************************** */ + +static void create_single_slice(VolumeSlicer *slicer, const float depth, + const int axis, const int idx) +{ + const float vertices[3][4][3] = { + { + { depth, slicer->min[1], slicer->min[2] }, + { depth, slicer->max[1], slicer->min[2] }, + { depth, slicer->max[1], slicer->max[2] }, + { depth, slicer->min[1], slicer->max[2] } + }, + { + { slicer->min[0], depth, slicer->min[2] }, + { slicer->min[0], depth, slicer->max[2] }, + { slicer->max[0], depth, slicer->max[2] }, + { slicer->max[0], depth, slicer->min[2] } + }, + { + { slicer->min[0], slicer->min[1], depth }, + { slicer->min[0], slicer->max[1], depth }, + { slicer->max[0], slicer->max[1], depth }, + { slicer->max[0], slicer->min[1], depth } + } + }; + + copy_v3_v3(slicer->verts[idx + 0], vertices[axis][0]); + copy_v3_v3(slicer->verts[idx + 1], vertices[axis][1]); + copy_v3_v3(slicer->verts[idx + 2], vertices[axis][2]); + copy_v3_v3(slicer->verts[idx + 3], vertices[axis][0]); + copy_v3_v3(slicer->verts[idx + 4], vertices[axis][2]); + copy_v3_v3(slicer->verts[idx + 5], vertices[axis][3]); +} + +static void create_axis_aligned_slices(VolumeSlicer *slicer, const int num_slices, + const float view_dir[3], const int axis) +{ + float depth, slice_size = slicer->size[axis] / num_slices; + + /* always process slices in back to front order! */ + if (view_dir[axis] > 0.0f) { + depth = slicer->min[axis]; + } + else { + depth = slicer->max[axis]; + slice_size = -slice_size; + } + + int count = 0; + for (int slice = 0; slice < num_slices; slice++) { + create_single_slice(slicer, depth, axis, count); + + count += 6; + depth += slice_size; + } +} + /* *************************** View Aligned Slicing ************************** */ /* Code adapted from: @@ -433,8 +490,25 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, /* setup slicing information */ - const int max_slices = 256; - const int max_points = max_slices * 12; + const bool view_aligned = (sds->slice_method == MOD_SMOKE_SLICE_VIEW_ALIGNED); + int max_slices, max_points, axis = 0; + + if (view_aligned) { + max_slices = max_iii(sds->res[0], sds->res[1], sds->res[2]) * sds->slice_per_voxel; + max_points = max_slices * 12; + } + else { + if (sds->axis_slice_method == AXIS_SLICE_FULL) { + axis = axis_dominant_v3_single(viewnormal); + max_slices = sds->res[axis] * sds->slice_per_voxel; + } + else { + axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewnormal) : sds->slice_axis - 1; + max_slices = 1; + } + + max_points = max_slices * 6; + } VolumeSlicer slicer; copy_v3_v3(slicer.min, min); @@ -442,7 +516,22 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, copy_v3_v3(slicer.size, size); slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices"); - const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); + int num_points; + + if (view_aligned) { + num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); + } + else { + num_points = max_points; + + if (sds->axis_slice_method == AXIS_SLICE_FULL) { + create_axis_aligned_slices(&slicer, max_slices, viewnormal, axis); + } + else { + const float depth = (sds->slice_depth - 0.5f) * size[axis]; + create_single_slice(&slicer, depth, axis, 0); + } + } /* setup buffer and draw */ diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 76de8443faa..5526c18f656 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -52,6 +52,26 @@ enum { /* viewsettings */ #define MOD_SMOKE_VIEW_SHOWBIG (1<<0) +/* slice method */ +enum { + MOD_SMOKE_SLICE_VIEW_ALIGNED = 0, + MOD_SMOKE_SLICE_AXIS_ALIGNED = 1, +}; + +/* axis aligned method */ +enum { + AXIS_SLICE_FULL = 0, + AXIS_SLICE_SINGLE = 1, +}; + +/* single slice direction */ +enum { + SLICE_AXIS_AUTO = 0, + SLICE_AXIS_X = 1, + SLICE_AXIS_Y = 2, + SLICE_AXIS_Z = 3, +}; + /* cache compression */ #define SM_CACHE_LIGHT 0 #define SM_CACHE_HEAVY 1 @@ -161,6 +181,13 @@ typedef struct SmokeDomainSettings { float burning_rate, flame_smoke, flame_vorticity; float flame_ignition, flame_max_temp; float flame_smoke_color[3]; + + /* Display settings */ + char slice_method, axis_slice_method; + char slice_axis, pad2; + float slice_per_voxel; + float slice_depth; + float display_thickness; } SmokeDomainSettings; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index dad5577dc12..22c1a115a15 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -443,6 +443,26 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem smoke_view_items[] = { + {MOD_SMOKE_SLICE_VIEW_ALIGNED, "VIEW_ALIGNED", 0, "View", "Slice volume parallel to the view plane"}, + {MOD_SMOKE_SLICE_AXIS_ALIGNED, "AXIS_ALIGNED", 0, "Axis", "Slice volume parallel to the major axis"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem axis_slice_method_items[] = { + {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"}, + {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"}, + {0, NULL, 0, NULL, NULL} + }; + + static 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"}, + {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"}, + {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL); RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings"); RNA_def_struct_sdna(srna, "SmokeDomainSettings"); @@ -719,6 +739,48 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL); RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); + + /* display settings */ + + prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "slice_method"); + RNA_def_property_enum_items(prop, smoke_view_items); + RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method"); + RNA_def_property_enum_items(prop, axis_slice_method_items); + RNA_def_property_ui_text(prop, "Method", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "slice_axis"); + RNA_def_property_enum_items(prop, axis_slice_position_items); + RNA_def_property_ui_text(prop, "Axis", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel"); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1); + RNA_def_property_ui_text(prop, "Slice Per Voxel", + "How many slices per voxel should be generated"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "slice_depth"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Position", "Position of the slice"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "display_thickness"); + RNA_def_property_range(prop, 0.001, 1000.0); + RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); } static void rna_def_smoke_flow_settings(BlenderRNA *brna)