Viewport smoke: add options to draw velocity vectors.
authorKévin Dietrich <kevin.dietrich@mailoo.org>
Sat, 24 Sep 2016 20:36:54 +0000 (22:36 +0200)
committerKévin Dietrich <kevin.dietrich@mailoo.org>
Sat, 24 Sep 2016 20:36:54 +0000 (22:36 +0200)
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

release/scripts/startup/bl_ui/properties_physics_smoke.py
source/blender/blenkernel/intern/smoke.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/drawvolume.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/makesdna/DNA_smoke_types.h
source/blender/makesrna/intern/rna_smoke.c

index 829850e4f2f81013cbdd564dbf573f814625f401..3cf77135622bc790854344f2651b6c37127eda97 100644 (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__)
index d0f546e9bef9b483b27b26a2674a71c27735b7ed..05540f515880c81bb3b6ca9010cf944222d90c07 100644 (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;
index a74c0f0f46767f38390ab0f2d76ded7ea06a1e68..ea40d4eb5e11137d1351806e26241ed4eeaa0f53 100644 (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
index d743e7c09e794cce8a52917b7f8dc4a09ea976b2..ef4db7ed6b8bd25e8d9ec487ebc24dd9459d5a4b 100644 (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);
 
-       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 */
+       copy_v3_v3(colors[*offset + 0], rgb);
+       copy_v3_v3(colors[*offset + 1], rgb);
+       copy_v3_v3(colors[*offset + 2], rgb);
 
-       glLineWidth(1.0f);
+       *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 */
-       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;
+       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];
        add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
 
-       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 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 = sqrtf(vel_x[index] * vel_x[index] + vel_y[index] * vel_y[index] + vel_z[index] * vel_z[index]);
+                               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]
+                               };
 
-                               /* 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);
+                               float vel[3] = {
+                                   vel_x[index], vel_y[index], vel_z[index]
+                               };
 
-                                       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();
-                               }
+                               func(verts, colors, pos, vel, domain->vector_scale, cell_size[0], &num_points);
                        }
+               }
+       }
+
+       glLineWidth(1.0f);
+
+       glEnableClientState(GL_VERTEX_ARRAY);
+       glVertexPointer(3, GL_FLOAT, 0, verts);
+
+       glEnableClientState(GL_COLOR_ARRAY);
+       glColorPointer(3, GL_FLOAT, 0, colors);
+
+       glDrawArrays(GL_LINES, 0, num_points);
+
+       glDisableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_COLOR_ARRAY);
+
+       MEM_freeN(verts);
+       MEM_freeN(colors);
 }
-#endif
 
 #ifdef SMOKE_DEBUG_HEAT
 void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
index 314dadbaa52e26153e605b886f9a352c323e5aa8..0e2cb95dd898684556048e6f2bdc7f808254a2ca 100644 (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
index 5526c18f6568e0e32474c70c33cfbaf8fea1c438..ba7f73c2f638403b904eb30ffd7bb1349ced0b5b 100644 (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;
 
 
index 22c1a115a15dd2df33dc3ca842e3a38eae473487..40a45416acae10c110af2fe9133dbdbd6eae4711 100644 (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)