Blender  V2.93
sculpt_geodesic.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_blenlib.h"
27 #include "BLI_linklist_stack.h"
28 #include "BLI_math.h"
29 #include "BLI_task.h"
30 
31 #include "BLT_translation.h"
32 
33 #include "DNA_brush_types.h"
34 #include "DNA_mesh_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_object_types.h"
37 
38 #include "BKE_brush.h"
39 #include "BKE_ccg.h"
40 #include "BKE_colortools.h"
41 #include "BKE_context.h"
42 #include "BKE_image.h"
43 #include "BKE_mesh.h"
44 #include "BKE_mesh_mapping.h"
45 #include "BKE_multires.h"
46 #include "BKE_node.h"
47 #include "BKE_object.h"
48 #include "BKE_paint.h"
49 #include "BKE_pbvh.h"
50 #include "BKE_scene.h"
51 #include "BKE_subdiv_ccg.h"
52 
53 #include "DEG_depsgraph.h"
54 
55 #include "WM_api.h"
56 #include "WM_message.h"
57 #include "WM_toolsystem.h"
58 #include "WM_types.h"
59 
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 
63 #include "ED_object.h"
64 #include "ED_screen.h"
65 #include "ED_sculpt.h"
66 #include "ED_view3d.h"
67 #include "paint_intern.h"
68 #include "sculpt_intern.h"
69 
70 #include "IMB_colormanagement.h"
71 #include "IMB_imbuf.h"
72 
73 #include "bmesh.h"
74 
75 #include <math.h>
76 #include <stdlib.h>
77 #define SCULPT_GEODESIC_VERTEX_NONE -1
78 
79 /* Propagate distance from v1 and v2 to v0. */
81  MVert *mvert, const int v0, const int v1, const int v2, float *dists, GSet *initial_vertices)
82 {
83  if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(v0))) {
84  return false;
85  }
86 
87  BLI_assert(dists[v1] != FLT_MAX);
88  if (dists[v0] <= dists[v1]) {
89  return false;
90  }
91 
92  float dist0;
94  BLI_assert(dists[v2] != FLT_MAX);
95  if (dists[v0] <= dists[v2]) {
96  return false;
97  }
99  mvert[v0].co, mvert[v1].co, mvert[v2].co, dists[v1], dists[v2]);
100  }
101  else {
102  float vec[3];
103  sub_v3_v3v3(vec, mvert[v1].co, mvert[v0].co);
104  dist0 = dists[v1] + len_v3(vec);
105  }
106 
107  if (dist0 < dists[v0]) {
108  dists[v0] = dist0;
109  return true;
110  }
111 
112  return false;
113 }
114 
116  GSet *initial_vertices,
117  const float limit_radius)
118 {
119  SculptSession *ss = ob->sculpt;
121 
122  const int totvert = mesh->totvert;
123  const int totedge = mesh->totedge;
124 
125  const float limit_radius_sq = limit_radius * limit_radius;
126 
127  MEdge *edges = mesh->medge;
129 
130  float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances");
131  BLI_bitmap *edge_tag = BLI_BITMAP_NEW(totedge, "edge tag");
132 
133  if (!ss->epmap) {
135  &ss->epmap_mem,
136  mesh->medge,
137  mesh->totedge,
138  mesh->mpoly,
139  mesh->totpoly,
140  mesh->mloop,
141  mesh->totloop);
142  }
143  if (!ss->vemap) {
145  &ss->vemap, &ss->vemap_mem, mesh->medge, mesh->totvert, mesh->totedge);
146  }
147 
148  /* Both contain edge indices encoded as *void. */
149  BLI_LINKSTACK_DECLARE(queue, void *);
150  BLI_LINKSTACK_DECLARE(queue_next, void *);
151 
153  BLI_LINKSTACK_INIT(queue_next);
154 
155  for (int i = 0; i < totvert; i++) {
156  if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(i))) {
157  dists[i] = 0.0f;
158  }
159  else {
160  dists[i] = FLT_MAX;
161  }
162  }
163 
164  /* Masks vertices that are further than limit radius from an initial vertex. As there is no need
165  * to define a distance to them the algorithm can stop earlier by skipping them. */
166  BLI_bitmap *affected_vertex = BLI_BITMAP_NEW(totvert, "affected vertex");
167  GSetIterator gs_iter;
168 
169  if (limit_radius == FLT_MAX) {
170  /* In this case, no need to loop through all initial vertices to check distances as they are
171  * all going to be affected. */
172  BLI_bitmap_set_all(affected_vertex, true, totvert);
173  }
174  else {
175  /* This is an O(n^2) loop used to limit the geodesic distance calculation to a radius. When
176  * this optimization is needed, it is expected for the tool to request the distance to a low
177  * number of vertices (usually just 1 or 2). */
178  GSET_ITER (gs_iter, initial_vertices) {
179  const int v = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
180  float *v_co = verts[v].co;
181  for (int i = 0; i < totvert; i++) {
182  if (len_squared_v3v3(v_co, verts[i].co) <= limit_radius_sq) {
183  BLI_BITMAP_ENABLE(affected_vertex, i);
184  }
185  }
186  }
187  }
188 
189  /* Add edges adjacent to an initial vertex to the queue. */
190  for (int i = 0; i < totedge; i++) {
191  const int v1 = edges[i].v1;
192  const int v2 = edges[i].v2;
193  if (!BLI_BITMAP_TEST(affected_vertex, v1) && !BLI_BITMAP_TEST(affected_vertex, v2)) {
194  continue;
195  }
196  if (dists[v1] != FLT_MAX || dists[v2] != FLT_MAX) {
198  }
199  }
200 
201  do {
202  while (BLI_LINKSTACK_SIZE(queue)) {
203  const int e = POINTER_AS_INT(BLI_LINKSTACK_POP(queue));
204  int v1 = edges[e].v1;
205  int v2 = edges[e].v2;
206 
207  if (dists[v1] == FLT_MAX || dists[v2] == FLT_MAX) {
208  if (dists[v1] > dists[v2]) {
209  SWAP(int, v1, v2);
210  }
212  verts, v2, v1, SCULPT_GEODESIC_VERTEX_NONE, dists, initial_vertices);
213  }
214 
215  if (ss->epmap[e].count != 0) {
216  for (int poly_map_index = 0; poly_map_index < ss->epmap[e].count; poly_map_index++) {
217  const int poly = ss->epmap[e].indices[poly_map_index];
218  if (ss->face_sets[poly] <= 0) {
219  continue;
220  }
221  const MPoly *mpoly = &mesh->mpoly[poly];
222 
223  for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
224  const MLoop *mloop = &mesh->mloop[loop_index + mpoly->loopstart];
225  const int v_other = mloop->v;
226  if (ELEM(v_other, v1, v2)) {
227  continue;
228  }
230  verts, v_other, v1, v2, dists, initial_vertices)) {
231  for (int edge_map_index = 0; edge_map_index < ss->vemap[v_other].count;
232  edge_map_index++) {
233  const int e_other = ss->vemap[v_other].indices[edge_map_index];
234  int ev_other;
235  if (edges[e_other].v1 == (uint)v_other) {
236  ev_other = edges[e_other].v2;
237  }
238  else {
239  ev_other = edges[e_other].v1;
240  }
241 
242  if (e_other != e && !BLI_BITMAP_TEST(edge_tag, e_other) &&
243  (ss->epmap[e_other].count == 0 || dists[ev_other] != FLT_MAX)) {
244  if (BLI_BITMAP_TEST(affected_vertex, v_other) ||
245  BLI_BITMAP_TEST(affected_vertex, ev_other)) {
246  BLI_BITMAP_ENABLE(edge_tag, e_other);
247  BLI_LINKSTACK_PUSH(queue_next, POINTER_FROM_INT(e_other));
248  }
249  }
250  }
251  }
252  }
253  }
254  }
255  }
256 
257  for (LinkNode *lnk = queue_next; lnk; lnk = lnk->next) {
258  const int e = POINTER_AS_INT(lnk->link);
259  BLI_BITMAP_DISABLE(edge_tag, e);
260  }
261 
262  BLI_LINKSTACK_SWAP(queue, queue_next);
263 
264  } while (BLI_LINKSTACK_SIZE(queue));
265 
267  BLI_LINKSTACK_FREE(queue_next);
268  MEM_SAFE_FREE(edge_tag);
269  MEM_SAFE_FREE(affected_vertex);
270 
271  return dists;
272 }
273 
274 /* For sculpt mesh data that does not support a geodesic distances algorithm, fallback to the
275  * distance to each vertex. In this case, only one of the initial vertices will be used to
276  * calculate the distance. */
277 static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices)
278 {
279 
280  SculptSession *ss = ob->sculpt;
282  const int totvert = mesh->totvert;
283  float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances");
284  int first_affected = SCULPT_GEODESIC_VERTEX_NONE;
285  GSetIterator gs_iter;
286  GSET_ITER (gs_iter, initial_vertices) {
287  first_affected = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
288  break;
289  }
290 
291  if (first_affected == SCULPT_GEODESIC_VERTEX_NONE) {
292  for (int i = 0; i < totvert; i++) {
293  dists[i] = FLT_MAX;
294  }
295  return dists;
296  }
297 
298  const float *first_affected_co = SCULPT_vertex_co_get(ss, first_affected);
299  for (int i = 0; i < totvert; i++) {
300  dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, i));
301  }
302 
303  return dists;
304 }
305 
307  GSet *initial_vertices,
308  const float limit_radius)
309 {
310  SculptSession *ss = ob->sculpt;
311  switch (BKE_pbvh_type(ss->pbvh)) {
312  case PBVH_FACES:
313  return SCULPT_geodesic_mesh_create(ob, initial_vertices, limit_radius);
314  case PBVH_BMESH:
315  case PBVH_GRIDS:
316  return SCULPT_geodesic_fallback_create(ob, initial_vertices);
317  }
318  BLI_assert(false);
319  return NULL;
320 }
321 
323  Object *ob,
324  const int vertex,
325  const float limit_radius)
326 {
327  SculptSession *ss = ob->sculpt;
328  GSet *initial_vertices = BLI_gset_int_new("initial_vertices");
329 
330  const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
331  for (char i = 0; i <= symm; ++i) {
332  if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
333  int v = -1;
334  if (i == 0) {
335  v = vertex;
336  }
337  else {
338  float location[3];
339  flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i);
340  v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
341  }
342  if (v != -1) {
343  BLI_gset_add(initial_vertices, POINTER_FROM_INT(v));
344  }
345  }
346  }
347 
348  float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius);
349  BLI_gset_free(initial_vertices, NULL);
350  return dists;
351 }
352 
353 float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius)
354 {
355  GSet *initial_vertices = BLI_gset_int_new("initial_vertices");
356  BLI_gset_add(initial_vertices, POINTER_FROM_INT(vertex));
357  float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius);
358  BLI_gset_free(initial_vertices, NULL);
359  return dists;
360 }
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, const int totedge, const struct MPoly *mpoly, const int totpoly, const struct MLoop *mloop, const int totloop)
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge)
General operations, lookup, etc. for blender objects.
struct Mesh * BKE_object_get_original_mesh(struct Object *object)
Definition: object.c:4493
A BVH for high poly meshes.
PBVHType BKE_pbvh_type(const PBVH *pbvh)
Definition: pbvh.c:1661
@ PBVH_GRIDS
Definition: BKE_pbvh.h:211
@ PBVH_BMESH
Definition: BKE_pbvh.h:212
@ PBVH_FACES
Definition: BKE_pbvh.h:210
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_DISABLE(_bitmap, _index)
Definition: BLI_bitmap.h:83
#define BLI_BITMAP_NEW(_tot, _alloc_string)
Definition: BLI_bitmap.h:50
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
Definition: bitmap.c:33
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
struct GSet GSet
Definition: BLI_ghash.h:189
GSet * BLI_gset_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
#define GSET_ITER(gs_iter_, gset_)
Definition: BLI_ghash.h:268
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:255
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
float geodesic_distance_propagate_across_triangle(const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
Definition: math_geom.c:6264
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
Object is a sort of wrapper for general info.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static float verts[][3]
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
ThreadQueue * queue
all scheduled work for the cpu
void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm)
Definition: paint_utils.c:407
const float * SCULPT_vertex_co_get(SculptSession *ss, int index)
Definition: sculpt.c:134
int SCULPT_nearest_vertex_get(Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
Definition: sculpt.c:1000
bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
Definition: sculpt.c:1042
char SCULPT_mesh_symmetry_xyz_get(Object *object)
Definition: sculpt.c:323
MVert * SCULPT_mesh_deformed_mverts_get(SculptSession *ss)
Definition: sculpt.c:295
static bool sculpt_geodesic_mesh_test_dist_add(MVert *mvert, const int v0, const int v1, const int v2, float *dists, GSet *initial_vertices)
float * SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, Object *ob, const int vertex, const float limit_radius)
float * SCULPT_geodesic_distances_create(Object *ob, GSet *initial_vertices, const float limit_radius)
float * SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius)
static float * SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices)
static float * SCULPT_geodesic_mesh_create(Object *ob, GSet *initial_vertices, const float limit_radius)
#define SCULPT_GEODESIC_VERTEX_NONE
struct LinkNode * next
Definition: BLI_linklist.h:39
unsigned int v1
unsigned int v2
unsigned int v
struct MEdge * medge
int totedge
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
struct SculptSession * sculpt
struct MeshElemMap * epmap
Definition: BKE_paint.h:478
int * face_sets
Definition: BKE_paint.h:490
struct MeshElemMap * vemap
Definition: BKE_paint.h:482
int * epmap_mem
Definition: BKE_paint.h:479
struct PBVH * pbvh
Definition: BKE_paint.h:504
int * vemap_mem
Definition: BKE_paint.h:483