[Bf-blender-cvs] [4b4ac93acd9] temp_bmesh_multires: Sculpt dyntopo: Wrote a little UV smoother sculpt brush. It uses a simple LSCM-like solver; hold ctrl to do simple laplacian relaxation.

Joseph Eagar noreply at git.blender.org
Sun Jul 11 10:12:55 CEST 2021


Commit: 4b4ac93acd96818373834233d68099c652ea28ec
Author: Joseph Eagar
Date:   Sun Jul 11 03:43:47 2021 -0400
Branches: temp_bmesh_multires
https://developer.blender.org/rB4b4ac93acd96818373834233d68099c652ea28ec

Sculpt dyntopo: Wrote a little UV smoother sculpt brush.
It uses a simple LSCM-like solver; hold ctrl to do simple
laplacian relaxation.

There are some interesting artistic possibilities to using
DynTopo with UV maps, the point of this tool is to help
explore them.

Note that I'm not planning to merge this into master with
the rest of this branch.  When the time comes I plan to
move it into a new branch for sculpt research stuff.

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

M	release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_dyntopo.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/makesdna/DNA_brush_enums.h
M	source/blender/makesdna/DNA_userdef_types.h
M	source/blender/makesrna/intern/rna_brush.c
M	source/blender/makesrna/intern/rna_userdef.c

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

diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index c55f637f8b2..ea48c2ff0d4 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1286,6 +1286,8 @@ class _defs_sculpt:
         prefs = bpy.context.preferences
         if not prefs.experimental.use_sculpt_vertex_colors:
             exclude_filter = {'PAINT', 'SMEAR'}
+        if not prefs.experimental.use_sculpt_uvsmooth:
+            exclude_filter.add('UV_SMOOTH')
 
         return generate_from_enum_ex(
             context,
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index e259aac5fb7..bb894d44593 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -3138,7 +3138,8 @@ static float brush_strength(const Sculpt *sd,
       return flip * alpha * pressure * feather;
     case SCULPT_TOOL_VCOL_BOUNDARY:
       return flip * alpha * pressure * feather;
-
+    case SCULPT_TOOL_UV_SMOOTH:
+      return flip * alpha * pressure * feather;
     case SCULPT_TOOL_PINCH:
       if (flip > 0.0f) {
         return alpha * flip * pressure * overlap * feather;
@@ -7109,6 +7110,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
     case SCULPT_TOOL_VCOL_BOUNDARY:
       SCULPT_smooth_vcol_boundary(sd, ob, nodes, totnode, ss->cache->bstrength);
       break;
+    case SCULPT_TOOL_UV_SMOOTH:
+      SCULPT_uv_brush(sd, ob, nodes, totnode);
+      break;
   }
 
   bool apply_autosmooth = !ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
@@ -7758,6 +7762,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
       return "Smear Brush";
     case SCULPT_TOOL_VCOL_BOUNDARY:
       return "Color Boundary";
+    case SCULPT_TOOL_UV_SMOOTH:
+      return "UV Smooth";
   }
 
   return "Sculpting";
@@ -8376,6 +8382,7 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
           ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) ||
           (brush->sculpt_tool == SCULPT_TOOL_POSE) ||
           (brush->sculpt_tool == SCULPT_TOOL_VCOL_BOUNDARY) ||
+          (brush->sculpt_tool == SCULPT_TOOL_UV_SMOOTH) ||
           (brush->sculpt_tool == SCULPT_TOOL_PAINT && brush->vcol_boundary_factor > 0.0f) ||
           (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) ||
           (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) ||
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 333667aef7d..88227339b5e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -41,6 +41,7 @@
 #include "DNA_modifier_types.h"
 
 #include "BKE_brush.h"
+#include "BKE_colortools.h"
 #include "BKE_context.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
@@ -897,3 +898,687 @@ void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
 
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
+
+#define MAXUVLOOPS 32
+#define MAXUVNEIGHBORS 32
+
+typedef struct UVSmoothVert {
+  double uv[2];
+  float co[3];  // world co
+  BMVert *v;
+  double w;
+  int totw;
+  bool pinned;
+  BMLoop *ls[MAXUVLOOPS];
+  struct UVSmoothVert *neighbors[MAXUVNEIGHBORS];
+  int totloop, totneighbor;
+} UVSmoothVert;
+
+typedef struct UVSmoothTri {
+  UVSmoothVert *vs[3];
+  float area2d, area3d;
+} UVSmoothTri;
+
+#define CON_MAX_VERTS 16
+typedef struct UVSmoothConstraint {
+  int type;
+  double k;
+  UVSmoothVert *vs[CON_MAX_VERTS];
+  UVSmoothTri *tri;
+  double gs[CON_MAX_VERTS][2];
+  int totvert;
+  double params[8];
+} UVSmoothConstraint;
+
+enum { CON_ANGLES = 0, CON_AREA = 1 };
+
+typedef struct UVSolver {
+  BLI_mempool *verts;
+  BLI_mempool *tris;
+  int totvert, tottri;
+  float snap_limit;
+  BLI_mempool *constraints;
+  GHash *vhash;
+  GHash *fhash;
+  int cd_uv;
+
+  double totarea3d;
+  double totarea2d;
+
+  double strength;
+} UVSolver;
+
+typedef struct SculptUVThreadData {
+  SculptThreadedTaskData data;
+  UVSolver *solver;
+} SculptUVThreadData;
+
+static UVSolver *uvsolver_new(int cd_uv)
+{
+  UVSolver *solver = MEM_callocN(sizeof(*solver), "solver");
+
+  solver->strength = 1.0;
+  solver->cd_uv = cd_uv;
+  solver->snap_limit = 0.01;
+
+  solver->verts = BLI_mempool_create(sizeof(UVSmoothVert), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+  solver->tris = BLI_mempool_create(sizeof(UVSmoothTri), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+  solver->constraints = BLI_mempool_create(
+      sizeof(UVSmoothConstraint), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+
+  solver->vhash = BLI_ghash_ptr_new("uvsolver");
+  solver->fhash = BLI_ghash_ptr_new("uvsolver");
+
+  return solver;
+}
+
+static void uvsolver_free(UVSolver *solver)
+{
+  BLI_mempool_destroy(solver->verts);
+  BLI_mempool_destroy(solver->tris);
+  BLI_mempool_destroy(solver->constraints);
+
+  BLI_ghash_free(solver->vhash, NULL, NULL);
+  BLI_ghash_free(solver->fhash, NULL, NULL);
+
+  MEM_freeN(solver);
+}
+
+void *uvsolver_calc_loop_key(UVSolver *solver, BMLoop *l)
+{
+  // return (void *)l->v;
+  MLoopUV *uv = BM_ELEM_CD_GET_VOID_P(l, solver->cd_uv);
+
+  float u = floorf(uv->uv[0] / solver->snap_limit) * solver->snap_limit;
+  float v = floorf(uv->uv[1] / solver->snap_limit) * solver->snap_limit;
+
+  intptr_t x = (intptr_t)(uv->uv[0] * 16384.0);
+  intptr_t y = (intptr_t)(uv->uv[1] * 16384.0);
+  intptr_t key = y * 16384LL + x;
+
+  return POINTER_FROM_INT(key);
+}
+
+static UVSmoothVert *uvsolver_get_vert(UVSolver *solver, BMLoop *l)
+{
+  MLoopUV *uv = BM_ELEM_CD_GET_VOID_P(l, solver->cd_uv);
+
+  void *pkey = uvsolver_calc_loop_key(solver, l);
+  void **entry = NULL;
+  UVSmoothVert *v;
+
+  if (!BLI_ghash_ensure_p(solver->vhash, pkey, &entry)) {
+    v = BLI_mempool_alloc(solver->verts);
+    memset(v, 0, sizeof(*v));
+
+    // copy_v2_v2(v->uv, uv->uv);
+    v->uv[0] = (double)uv->uv[0];
+    v->uv[1] = (double)uv->uv[1];
+
+    copy_v3_v3(v->co, l->v->co);
+    v->v = l->v;
+
+    *entry = (void *)v;
+  }
+
+  v = (UVSmoothVert *)*entry;
+
+  if (v->totloop < MAXUVLOOPS) {
+    v->ls[v->totloop++] = l;
+  }
+
+  return v;
+}
+
+MINLINE double area_tri_signed_v2_db(const double v1[2], const double v2[2], const double v3[2])
+{
+  return 0.5f * ((v1[0] - v2[0]) * (v2[1] - v3[1]) + (v1[1] - v2[1]) * (v3[0] - v2[0]));
+}
+
+MINLINE double area_tri_v2_db(const double v1[2], const double v2[2], const double v3[2])
+{
+  return fabsf(area_tri_signed_v2_db(v1, v2, v3));
+}
+
+void cross_tri_v3_db(double n[3], const double v1[3], const double v2[3], const double v3[3])
+{
+  double n1[3], n2[3];
+
+  n1[0] = v1[0] - v2[0];
+  n2[0] = v2[0] - v3[0];
+  n1[1] = v1[1] - v2[1];
+  n2[1] = v2[1] - v3[1];
+  n1[2] = v1[2] - v2[2];
+  n2[2] = v2[2] - v3[2];
+  n[0] = n1[1] * n2[2] - n1[2] * n2[1];
+  n[1] = n1[2] * n2[0] - n1[0] * n2[2];
+  n[2] = n1[0] * n2[1] - n1[1] * n2[0];
+}
+
+double area_tri_v3_db(const double v1[3], const double v2[3], const double v3[3])
+{
+  double n[3];
+  cross_tri_v3_db(n, v1, v2, v3);
+  return len_v3_db(n) * 0.5;
+}
+
+static UVSmoothTri *uvsolver_ensure_face(UVSolver *solver, BMFace *f)
+{
+  void **entry = NULL;
+
+  if (BLI_ghash_ensure_p(solver->fhash, (void *)f, &entry)) {
+    return (UVSmoothTri *)*entry;
+  }
+
+  UVSmoothTri *tri = BLI_mempool_alloc(solver->tris);
+  memset((void *)tri, 0, sizeof(*tri));
+  *entry = (void *)tri;
+
+  BMLoop *l = f->l_first;
+
+  bool nocon = false;
+  int i = 0;
+  do {
+    UVSmoothVert *sv = uvsolver_get_vert(solver, l);
+
+    if (BM_elem_flag_test(l->e, BM_ELEM_SEAM)) {
+      nocon = true;
+    }
+
+    tri->vs[i] = sv;
+
+    if (i > 3) {
+      // bad!
+      break;
+    }
+
+    i++;
+  } while ((l = l->next) != f->l_first);
+
+  double area3d = (double)area_tri_v3(tri->vs[0]->co, tri->vs[1]->co, tri->vs[2]->co);
+  double area2d = area_tri_v2_db(tri->vs[0]->uv, tri->vs[1]->uv, tri->vs[2]->uv);
+
+  if (area2d < 0.000001) {
+    tri->vs[0]->uv[0] -= 0.0001;
+    tri->vs[0]->uv[1] -= 0.0001;
+    tri->vs[1]->uv[0] += 0.0001;
+    tri->vs[2]->uv[1] += 0.0001;
+  }
+
+  solver->totarea2d += area2d;
+  solver->totarea3d += area3d;
+
+  tri->area2d = area2d;
+  tri->area3d = area3d;
+
+  for (int i = 0; !nocon && i < 3; i++) {
+
+    UVSmoothConstraint *con = BLI_mempool_alloc(solver->constraints);
+    memset((void *)con, 0, sizeof(*con));
+    con->type = CON_ANGLES;
+    con->k = 0.5;
+
+    UVSmoothVert *v0 = tri->vs[(i + 2) % 3];
+    UVSmoothVert *v1 = tri->vs[i];
+    UVSmoothVert *v2 = tri->vs[(i + 1) % 3];
+
+    con->vs[0] = v0;
+    con->vs[1] = v1;
+    con->vs[2] = v2;
+    con->totvert = 3;
+
+    float t1[3], t2[3];
+
+    sub_v3_v3v3(t1, v0->co, v1->co);
+    sub_v3_v3v3(t2, v2->co, v1->co);
+
+    normalize_v3(t1);
+    normalize_v3(t2);
+
+    float th3d = saacosf(dot_v3v3(t1, t2));
+
+    con->params[0] = (double)th3d;
+
+    // area constraint
+    con = BLI_mempool_alloc(solver->constraints);
+    memset((void *)con, 0, sizeof(*con));
+
+    con->vs[0] = v0;
+    con->vs[1] = v1;
+    con->vs[2] = v2;
+    con->totvert = 3;
+    con->tri = tri;
+    con->type = CON_AREA;
+    con->k = 1.0;
+  }
+
+#if 1
+  for (int i = 0; i < 3; i++) {
+    UVSmoothVert *v1 = tri->vs[i];
+    UVSmoothVert *v2 = tri->vs[(i + 1) % 3];
+
+    bool ok = true;
+
+    for (int j = 0; j < v1->totneighbor; j++) {
+      if (v1->neighbors[j] == v2) {
+        ok = false;
+        break;
+      }
+    }
+
+    ok = ok && v1->totneighbor < MAXUVNEIGHBORS && v2->totneighbor < MAXUVNEIGHBORS;
+
+    if (!ok) {
+      continue;
+    }
+
+    v1->neighbors[v1->totneighbor++] = v2;
+    v2->neighbors[v2->totneighbor++] = v1;
+  }
+#endif
+
+  return tri;
+}
+
+static double normalize_v2_db(double v[2])
+{
+  double len = v[0] * v[0] + v[1] * v[1];
+
+  if (len < 0.0000001) {
+    v[0] = v[1] = 0.0;
+    return 0.0;
+  }
+
+  len = sqrt(len);
+
+  double mul = 1.0 / len;
+
+  v[0] *= mul;
+  v[1] *= mul;
+
+  return len;
+}
+
+static double uvsolver_eval_constraint(UVSolver *solver, UVSmoothConstraint *con)
+{
+  switch (con->type) {
+    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list