Viewport smoke: add options to draw velocity vectors.

This basically exposes to the UI a function that was only available
through a debug macro ; the purpose is obviously to help debugging
simulations. It adds ways to draw the vectors either as colored needles
or as arrows showing the direction of the vectors. The colors are based
on the magnitude of the underlying vectors.

Reviewers: plasmasolutions, gottfried

Differential Revision: https://developer.blender.org/D1733
This commit is contained in:
Kévin Dietrich 2016-09-24 22:36:54 +02:00
parent 4446acbf17
commit 14e825aa1f
Notes: blender-bot 2023-02-14 09:36:46 +01:00
Referenced by issue #49445, does not compile WITH_MOD_SMOKE disabled
7 changed files with 215 additions and 52 deletions

View File

@ -383,6 +383,14 @@ class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
if axis_slice_method == 'FULL':
layout.prop(domain, "slice_per_voxel")
layout.separator()
layout.label(text="Debug:")
layout.prop(domain, "draw_velocity")
col = layout.column();
col.enabled = domain.draw_velocity
col.prop(domain, "vector_draw_type")
col.prop(domain, "vector_scale")
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@ -543,6 +543,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->slice_per_voxel = 5.0f;
smd->domain->slice_depth = 0.5f;
smd->domain->slice_axis = 0;
smd->domain->vector_scale = 1.0f;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@ -642,6 +643,9 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
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;
tsmd->domain->draw_velocity = smd->domain->draw_velocity;
tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
tsmd->domain->vector_scale = smd->domain->vector_scale;
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;

View File

@ -7912,9 +7912,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* smoke debug render */
#ifdef SMOKE_DEBUG_VELOCITY
draw_smoke_velocity(smd->domain, ob);
#endif
if (!render_override && sds->draw_velocity) {
draw_smoke_velocity(sds, viewnormal);
}
#ifdef SMOKE_DEBUG_HEAT
draw_smoke_heat(smd->domain, ob);
#endif

View File

@ -40,6 +40,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BKE_DerivedMesh.h"
#include "BKE_particle.h"
#include "smoke_API.h"
@ -571,61 +572,180 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
}
}
#ifdef SMOKE_DEBUG_VELOCITY
void draw_smoke_velocity(SmokeDomainSettings *domain, Object *ob)
static void add_tri(float (*verts)[3], float(*colors)[3], int *offset,
float p1[3], float p2[3], float p3[3], float rgb[3])
{
float x, y, z;
float x0, y0, z0;
int *base_res = domain->base_res;
int *res = domain->res;
int *res_min = domain->res_min;
int *res_max = domain->res_max;
float *vel_x = smoke_get_velocity_x(domain->fluid);
float *vel_y = smoke_get_velocity_y(domain->fluid);
float *vel_z = smoke_get_velocity_z(domain->fluid);
copy_v3_v3(verts[*offset + 0], p1);
copy_v3_v3(verts[*offset + 1], p2);
copy_v3_v3(verts[*offset + 2], p3);
copy_v3_v3(colors[*offset + 0], rgb);
copy_v3_v3(colors[*offset + 1], rgb);
copy_v3_v3(colors[*offset + 2], rgb);
*offset += 3;
}
static void add_needle(float (*verts)[3], float (*colors)[3], float center[3],
float dir[3], float scale, float voxel_size, int *offset)
{
float len = len_v3(dir);
float rgb[3];
weight_to_rgb(rgb, len);
if (len != 0.0f) {
mul_v3_fl(dir, 1.0f / len);
len *= scale;
}
len *= voxel_size;
float corners[4][3] = {
{ 0.0f, 0.2f, -0.5f },
{ -0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
{ 0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
{ 0.0f, 0.0f, 0.5f }
};
const float up[3] = { 0.0f, 0.0f, 1.0f };
float rot[3][3];
rotation_between_vecs_to_mat3(rot, up, dir);
transpose_m3(rot);
for (int i = 0; i < 4; i++) {
mul_m3_v3(rot, corners[i]);
mul_v3_fl(corners[i], len);
add_v3_v3(corners[i], center);
}
add_tri(verts, colors, offset, corners[0], corners[1], corners[2], rgb);
add_tri(verts, colors, offset, corners[0], corners[1], corners[3], rgb);
add_tri(verts, colors, offset, corners[1], corners[2], corners[3], rgb);
add_tri(verts, colors, offset, corners[2], corners[0], corners[3], rgb);
}
static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3],
float dir[3], float scale, float voxel_size, int *offset)
{
const float len = len_v3(dir);
float rgb[3];
weight_to_rgb(rgb, len);
copy_v3_v3(colors[(*offset)], rgb);
copy_v3_v3(verts[(*offset)++], center);
mul_v3_fl(dir, scale * voxel_size);
add_v3_v3(center, dir);
copy_v3_v3(colors[(*offset)], rgb);
copy_v3_v3(verts[(*offset)++], center);
}
typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float*, float*, float, float, int*);
void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
{
const int *base_res = domain->base_res;
const int *res = domain->res;
const int *res_min = domain->res_min;
int res_max[3];
copy_v3_v3_int(res_max, domain->res_max);
const float *vel_x = smoke_get_velocity_x(domain->fluid);
const float *vel_y = smoke_get_velocity_y(domain->fluid);
const float *vel_z = smoke_get_velocity_z(domain->fluid);
const float *cell_size = domain->cell_size;
const float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.0f;
/* set first position so that it doesn't jump when domain moves */
float xyz[3] = {
res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size),
res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size),
res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size)
};
if (xyz[0] < res_min[0]) xyz[0] += step_size;
if (xyz[1] < res_min[1]) xyz[1] += step_size;
if (xyz[2] < res_min[2]) xyz[2] += step_size;
float min[3];
float *cell_size = domain->cell_size;
float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
float vf = domain->scale / 16.f * 2.f; /* velocity factor */
add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
int num_points_v[3] = {
((float)(res_max[0] - floor(xyz[0])) / step_size) + 0.5f,
((float)(res_max[1] - floor(xyz[1])) / step_size) + 0.5f,
((float)(res_max[2] - floor(xyz[2])) / step_size) + 0.5f
};
if (domain->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
domain->axis_slice_method == AXIS_SLICE_SINGLE)
{
const int axis = (domain->slice_axis == SLICE_AXIS_AUTO) ?
axis_dominant_v3_single(viewnormal) : domain->slice_axis - 1;
xyz[axis] = (float)res[axis] * domain->slice_depth;
num_points_v[axis] = 1;
res_max[axis] = xyz[axis] + 1;
}
vector_draw_func func;
int max_points;
if (domain->vector_draw_type == VECTOR_DRAW_NEEDLE) {
func = add_needle;
max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 4 * 3;
}
else {
func = add_streamline;
max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 2;
}
float (*verts)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
float (*colors)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
int num_points = 0;
for (float x = floor(xyz[0]); x < res_max[0]; x += step_size) {
for (float y = floor(xyz[1]); y < res_max[1]; y += step_size) {
for (float z = floor(xyz[2]); z < res_max[2]; z += step_size) {
int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
float pos[3] = {
min[0] + ((float)x + 0.5f) * cell_size[0],
min[1] + ((float)y + 0.5f) * cell_size[1],
min[2] + ((float)z + 0.5f) * cell_size[2]
};
float vel[3] = {
vel_x[index], vel_y[index], vel_z[index]
};
func(verts, colors, pos, vel, domain->vector_scale, cell_size[0], &num_points);
}
}
}
glLineWidth(1.0f);
/* set first position so that it doesn't jump when domain moves */
x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
if (x0 < res_min[0]) x0 += step_size;
if (y0 < res_min[1]) y0 += step_size;
if (z0 < res_min[2]) z0 += step_size;
add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, verts);
for (x = floor(x0); x < res_max[0]; x += step_size)
for (y = floor(y0); y < res_max[1]; y += step_size)
for (z = floor(z0); z < res_max[2]; z += step_size) {
int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, colors);
float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]};
float vel = sqrtf(vel_x[index] * vel_x[index] + vel_y[index] * vel_y[index] + vel_z[index] * vel_z[index]);
glDrawArrays(GL_LINES, 0, num_points);
/* draw heat as scaled "arrows" */
if (vel >= 0.01f) {
float col_g = 1.0f - vel;
CLAMP(col_g, 0.0f, 1.0f);
glColor3f(1.0f, col_g, 0.0f);
glPointSize(10.0f * vel);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glBegin(GL_LINES);
glVertex3f(pos[0], pos[1], pos[2]);
glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
glEnd();
glBegin(GL_POINTS);
glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
glEnd();
}
}
MEM_freeN(verts);
MEM_freeN(colors);
}
#endif
#ifdef SMOKE_DEBUG_HEAT
void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)

View File

@ -296,12 +296,10 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
const float min[3], const float max[3],
const float viewnormal[3]);
//#define SMOKE_DEBUG_VELOCITY
//#define SMOKE_DEBUG_HEAT
#ifdef SMOKE_DEBUG_VELOCITY
void draw_smoke_velocity(struct SmokeDomainSettings *domain, struct Object *ob);
#endif
void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]);
#ifdef SMOKE_DEBUG_HEAT
void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
#endif

View File

@ -72,6 +72,11 @@ enum {
SLICE_AXIS_Z = 3,
};
enum {
VECTOR_DRAW_NEEDLE = 0,
VECTOR_DRAW_STREAMLINE = 1,
};
/* cache compression */
#define SM_CACHE_LIGHT 0
#define SM_CACHE_HEAVY 1
@ -184,10 +189,13 @@ typedef struct SmokeDomainSettings {
/* Display settings */
char slice_method, axis_slice_method;
char slice_axis, pad2;
char slice_axis, draw_velocity;
float slice_per_voxel;
float slice_depth;
float display_thickness;
float vector_scale;
char vector_draw_type;
char pad2[3];
} SmokeDomainSettings;

View File

@ -463,6 +463,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem vector_draw_items[] = {
{VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Draw vectors as needles"},
{VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Draw vectors as streamlines"},
{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");
@ -781,6 +787,24 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
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);
prop = RNA_def_property(srna, "draw_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
RNA_def_property_ui_text(prop, "Draw Velocity", "Toggle visualation of the velocity field as needles");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "vector_draw_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
RNA_def_property_enum_items(prop, vector_draw_items);
RNA_def_property_ui_text(prop, "Draw Type", "");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vector_scale");
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)