[Bf-blender-cvs] [99a7c917eab] master: Sculpt: Dyntopo detail size edit operator

Pablo Dobarro noreply at git.blender.org
Fri Oct 30 18:14:02 CET 2020


Commit: 99a7c917eab7612bf4b3f00b1bf392a6fb143251
Author: Pablo Dobarro
Date:   Thu Oct 29 22:32:22 2020 +0100
Branches: master
https://developer.blender.org/rB99a7c917eab7612bf4b3f00b1bf392a6fb143251

Sculpt: Dyntopo detail size edit operator

This introduces a new operator to edit the detail size of constant
detail mode in dyntopo. The way this operator works and the
functionality it provides is similar to the "Voxel size edit" operator
for the voxel remesher.

It also includes a sample mode. When pressing Ctrl, the detail size
will be sampled from the surface under the cursor, updating the
preview in real time. This allows quick resolution changes without
using the operator multiple times.

The operator is set to Shift + D, replacing the old way to change
the constant detail size of dyntopo. Shift + R will remain available to
be enabled when the voxel remesher works with dyntopo. Deciding
if both detail sizes can be unified needs a separate discussion as the
new dyntopo can work with detail sizes in parts of the mesh that can
easily crash the remesher.

The structure of these operators is similar, but the data they control,
ranges, drawing and setup functions are completely different, making it
hard to merge them into one.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D9355

===================================================================

M	release/scripts/presets/keyconfig/keymap_data/blender_default.py
M	source/blender/blenkernel/BKE_paint.h
M	source/blender/editors/sculpt_paint/paint_cursor.c
M	source/blender/editors/sculpt_paint/sculpt.c

===================================================================

diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 3b97ccfbc9b..467eb317905 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -4400,7 +4400,7 @@ def km_sculpt(params):
          {"properties": [("use_normals", True), ("keep_previous_mask", True), ("invert", False), ("smooth_iterations", 0), ("create_face_set", False)]}),
         # Dynamic topology
         ("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
-        ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+        ("sculpt.dyntopo_detail_size_edit", {"type": 'D', "value": 'PRESS', "shift": True}, None),
         # Remesh
         ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
         ("object.voxel_size_edit", {"type": 'R', "value": 'PRESS', "shift": True}, None),
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index f7038ed8f7f..bb1d1781e31 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -505,6 +505,9 @@ typedef struct SculptSession {
   int active_face_index;
   int active_grid_index;
 
+  /* When active, the cursor draws with faded colors, indicating that there is an action enabled.
+   */
+  bool draw_faded_cursor;
   float cursor_radius;
   float cursor_location[3];
   float cursor_normal[3];
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index f0285c8faf3..550913fc8af 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1310,6 +1310,11 @@ static bool paint_cursor_context_init(bContext *C,
   Object *active_object = pcontext->vc.obact;
   pcontext->ss = active_object ? active_object->sculpt : NULL;
 
+  if (pcontext->ss && pcontext->ss->draw_faded_cursor) {
+    pcontext->outline_alpha = 0.3f;
+    copy_v3_fl(pcontext->outline_col, 0.8f);
+  }
+
   pcontext->is_stroke_active = pcontext->ups->stroke_active;
 
   return true;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 74a54f9f6b7..754204201f4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -76,6 +76,11 @@
 
 #include "IMB_colormanagement.h"
 
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
 #include "WM_api.h"
 #include "WM_message.h"
 #include "WM_toolsystem.h"
@@ -84,6 +89,7 @@
 #include "ED_object.h"
 #include "ED_screen.h"
 #include "ED_sculpt.h"
+#include "ED_space_api.h"
 #include "ED_view3d.h"
 #include "paint_intern.h"
 #include "sculpt_intern.h"
@@ -9236,6 +9242,325 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
                 1.0f);
 }
 
+/* -------------------------------------------------------------------- */
+/** \name Dyntopo Detail Size Edit Operator
+ * \{ */
+
+/* Defines how much the mouse movement will modify the detail size value. */
+#define DETAIL_SIZE_DELTA_SPEED 0.08f
+#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
+
+typedef struct DyntopoDetailSizeEditCustomData {
+  void *draw_handle;
+  Object *active_object;
+
+  float init_mval[2];
+  float accurate_mval[2];
+
+  float outline_col[4];
+
+  bool accurate_mode;
+  bool sample_mode;
+
+  float init_detail_size;
+  float accurate_detail_size;
+  float detail_size;
+  float radius;
+
+  float preview_tri[3][3];
+  float gizmo_mat[4][4];
+} DyntopoDetailSizeEditCustomData;
+
+static void dyntopo_detail_size_parallel_lines_draw(uint pos3d,
+                                                    DyntopoDetailSizeEditCustomData *cd,
+                                                    const float start_co[3],
+                                                    const float end_co[3],
+                                                    bool flip,
+                                                    const float angle)
+{
+  float object_space_constant_detail = 1.0f /
+                                       (cd->detail_size * mat4_to_scale(cd->active_object->obmat));
+
+  /* The constant detail represents the maximum edge length allowed before subdividing it. If the
+   * triangle grid preview is created with this value it will represent an ideal mesh density where
+   * all edges have the exact maximum length, which never happens in practice. As the minimum edge
+   * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average
+   * between max and min edge length so the preview is more accurate. */
+  object_space_constant_detail *= 0.7f;
+
+  const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]);
+  const int tot_lines = (int)(total_len / object_space_constant_detail) + 1;
+  const float tot_lines_fl = total_len / object_space_constant_detail;
+  float spacing_disp[3];
+  sub_v3_v3v3(spacing_disp, end_co, start_co);
+  normalize_v3(spacing_disp);
+
+  float line_disp[3];
+  rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle));
+  mul_v3_fl(spacing_disp, total_len / tot_lines_fl);
+
+  immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2);
+  for (int i = 0; i < tot_lines; i++) {
+    float line_length;
+    if (flip) {
+      line_length = total_len * ((float)i / (float)tot_lines_fl);
+    }
+    else {
+      line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl));
+    }
+    float line_start[3];
+    copy_v3_v3(line_start, start_co);
+    madd_v3_v3v3fl(line_start, line_start, spacing_disp, i);
+    float line_end[3];
+    madd_v3_v3v3fl(line_end, line_start, line_disp, line_length);
+    immVertex3fv(pos3d, line_start);
+    immVertex3fv(pos3d, line_end);
+  }
+  immEnd();
+}
+
+static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C),
+                                          ARegion *UNUSED(ar),
+                                          void *arg)
+{
+  DyntopoDetailSizeEditCustomData *cd = arg;
+  GPU_blend(GPU_BLEND_ALPHA);
+  GPU_line_smooth(true);
+
+  uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+  immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+  GPU_matrix_push();
+  GPU_matrix_mul(cd->gizmo_mat);
+
+  /* Draw Cursor */
+  immUniformColor4fv(cd->outline_col);
+  GPU_line_width(3.0f);
+
+  imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80);
+
+  /* Draw Triangle. */
+  immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
+  immBegin(GPU_PRIM_LINES, 6);
+  immVertex3fv(pos3d, cd->preview_tri[0]);
+  immVertex3fv(pos3d, cd->preview_tri[1]);
+
+  immVertex3fv(pos3d, cd->preview_tri[1]);
+  immVertex3fv(pos3d, cd->preview_tri[2]);
+
+  immVertex3fv(pos3d, cd->preview_tri[2]);
+  immVertex3fv(pos3d, cd->preview_tri[0]);
+  immEnd();
+
+  /* Draw Grid */
+  GPU_line_width(1.0f);
+  dyntopo_detail_size_parallel_lines_draw(
+      pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f);
+  dyntopo_detail_size_parallel_lines_draw(
+      pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f);
+  dyntopo_detail_size_parallel_lines_draw(
+      pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f);
+  GPU_matrix_pop();
+
+  GPU_blend(GPU_BLEND_NONE);
+  GPU_line_smooth(false);
+}
+
+static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
+{
+  Object *active_object = CTX_data_active_object(C);
+  SculptSession *ss = active_object->sculpt;
+  ARegion *ar = CTX_wm_region(C);
+  DyntopoDetailSizeEditCustomData *cd = op->customdata;
+  ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+  ss->draw_faded_cursor = false;
+  MEM_freeN(op->customdata);
+  ED_workspace_status_text(C, NULL);
+}
+
+static void dyntopo_detail_size_sample_from_surface(Object *ob,
+                                                    DyntopoDetailSizeEditCustomData *cd)
+{
+  SculptSession *ss = ob->sculpt;
+  const int active_vertex = SCULPT_active_vertex_get(ss);
+
+  float len_accum = 0;
+  int num_neighbors = 0;
+  SculptVertexNeighborIter ni;
+  SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
+    len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
+                          SCULPT_vertex_co_get(ss, ni.index));
+    num_neighbors++;
+  }
+  SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+  if (num_neighbors > 0) {
+    const float avg_edge_len = len_accum / num_neighbors;
+    /* Use 0.7 as the average of min and max dyntopo edge length. */
+    const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat));
+    cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f);
+  }
+}
+
+static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd,
+                                                        const wmEvent *event)
+{
+  const float mval[2] = {event->mval[0], event->mval[1]};
+
+  float detail_size_delta;
+  if (cd->accurate_mode) {
+    detail_size_delta = mval[0] - cd->accurate_mval[0];
+    cd->detail_size = cd->accurate_detail_size +
+                      detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED;
+  }
+  else {
+    detail_size_delta = mval[0] - cd->init_mval[0];
+    cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED;
+  }
+
+  if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
+    cd->accurate_mode = true;
+    copy_v2_v2(cd->accurate_mval, mval);
+    cd->accurate_detail_size = cd->detail_size;
+  }
+  if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
+    cd->accurate_mode = false;
+    cd->accurate_detail_size = 0.0f;
+  }
+
+  cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f);
+}
+
+static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+  Object *active_object = CTX_data_active_object(C);
+  SculptSession *ss = active_object->sculpt;
+  ARegion *ar = CTX_wm_region(C);
+  DyntopoDetailSizeEditCustomData *cd = op->customdata;
+  Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+  /*

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list