forked from bartvdbraak/blender
Viewport smoke: add support for axis aligned slicing.
Current approach uses view aligned slicing to generate polygons for GL texturing such that the generated polygons are always facing the view plane. Now it is also possible to use object aligned slicing, which creates polygons by slicing the object perpendicular to whichever axis is facing the most the view plane. It is also possible to create a single slice for inspecting the volume, or for 2D rendering effects. Settings for this, along with a density multiplier setting, are to be found in a newly added "Smoke Display Settings" panel in the smoke domain properties tab. Reviewers: plasmasolutions, gottfried Differential Revision: https://developer.blender.org/D1733
This commit is contained in:
parent
a070a5befa
commit
4446acbf17
@ -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__)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user