Blender  V3.3
subdiv_displacement_multires.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2018 Blender Foundation. All rights reserved. */
3 
8 #include <math.h>
9 
10 #include "BKE_subdiv.h"
11 
12 #include "DNA_mesh_types.h"
13 #include "DNA_meshdata_types.h"
14 #include "DNA_modifier_types.h"
15 #include "DNA_object_types.h"
16 
17 #include "BLI_math_vector.h"
18 #include "BLI_utildefines.h"
19 
20 #include "BKE_customdata.h"
21 #include "BKE_multires.h"
22 #include "BKE_subdiv_eval.h"
23 
24 #include "MEM_guardedalloc.h"
25 
26 typedef struct PolyCornerIndex {
27  int poly_index;
28  int corner;
30 
31 typedef struct MultiresDisplacementData {
33  int grid_size;
34  /* Mesh is used to read external displacement. */
37  const MPoly *mpoly;
38  const MDisps *mdisps;
39  /* Indexed by ptex face index, contains polygon/corner which corresponds
40  * to it.
41  *
42  * NOTE: For quad polygon this is an index of first corner only, since
43  * there we only have one ptex. */
45  /* Indexed by coarse face index, returns first ptex face index corresponding
46  * to that coarse face. */
48  /* Sanity check, is used in debug builds.
49  * Controls that initialize() was called prior to eval_displacement(). */
52 
53 /* Denotes which grid to use to average value of the displacement read from the
54  * grid which corresponds to the ptex face. */
55 typedef enum eAverageWith {
61 
63  const int ptex_face_index,
64  const float u,
65  const float v,
66  const MDisps **r_displacement_grid,
67  float *grid_u,
68  float *grid_v)
69 {
70  MultiresDisplacementData *data = displacement->user_data;
71  const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
72  const MPoly *poly = &data->mpoly[poly_corner->poly_index];
73  const int start_grid_index = poly->loopstart + poly_corner->corner;
74  int corner = 0;
75  if (poly->totloop == 4) {
76  float corner_u, corner_v;
77  corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
78  *r_displacement_grid = &data->mdisps[start_grid_index + corner];
79  BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
80  }
81  else {
82  *r_displacement_grid = &data->mdisps[start_grid_index];
83  BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
84  }
85  return corner;
86 }
87 
89  const int ptex_face_index,
90  const int corner,
91  const int corner_delta)
92 {
93  MultiresDisplacementData *data = displacement->user_data;
94  const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
95  const MPoly *poly = &data->mpoly[poly_corner->poly_index];
96  const int effective_corner = (poly->totloop == 4) ? corner : poly_corner->corner;
97  const int next_corner = (effective_corner + corner_delta + poly->totloop) % poly->totloop;
98  return &data->mdisps[poly->loopstart + next_corner];
99 }
100 
102  const int grid_size,
103  const float grid_u,
104  const float grid_v,
105  float r_tangent_D[3])
106 {
107  if (displacement_grid->disps == NULL) {
108  zero_v3(r_tangent_D);
109  return AVERAGE_WITH_NONE;
110  }
111  const int x = roundf(grid_u * (grid_size - 1));
112  const int y = roundf(grid_v * (grid_size - 1));
113  copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]);
114  if (x == 0 && y == 0) {
115  return AVERAGE_WITH_ALL;
116  }
117  if (x == 0) {
118  return AVERAGE_WITH_PREV;
119  }
120  if (y == 0) {
121  return AVERAGE_WITH_NEXT;
122  }
123  return AVERAGE_WITH_NONE;
124 }
125 
127  const int corner,
128  const float grid_u,
129  const float grid_v,
130  float *r_ptex_face_u,
131  float *r_ptex_face_v)
132 {
133  if (poly->totloop == 4) {
134  BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
135  }
136  else {
137  BKE_subdiv_grid_uv_to_ptex_face_uv(grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
138  }
139 }
140 
142  const MPoly *poly,
143  const int ptex_face_index,
144  const int corner,
145  const float u,
146  const float v,
147  float r_tangent_matrix[3][3])
148 {
149  const bool is_quad = (poly->totloop == 4);
150  const int quad_corner = is_quad ? corner : 0;
151  float dummy_P[3], dPdu[3], dPdv[3];
152  BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
153  BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, quad_corner);
154 }
155 
157  const MDisps *other_displacement_grid,
158  const float grid_u,
159  const float grid_v,
160  float r_tangent_D[3])
161 {
162  read_displacement_grid(other_displacement_grid, data->grid_size, grid_u, grid_v, r_tangent_D);
163 }
164 
166  const MDisps *displacement_grid,
167  const float grid_u,
168  const float grid_v,
169  const int ptex_face_index,
170  const int corner_index,
171  float r_D[3])
172 {
173  const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
174  const MPoly *poly = &data->mpoly[poly_corner->poly_index];
175  /* Get (u, v) coordinate within the other ptex face which corresponds to
176  * the grid coordinates. */
177  float u, v;
178  average_convert_grid_coord_to_ptex(poly, corner_index, grid_u, grid_v, &u, &v);
179  /* Construct tangent matrix which corresponds to partial derivatives
180  * calculated for the other ptex face. */
181  float tangent_matrix[3][3];
183  data->subdiv, poly, ptex_face_index, corner_index, u, v, tangent_matrix);
184  /* Read displacement from other grid in a tangent space. */
185  float tangent_D[3];
186  average_read_displacement_tangent(data, displacement_grid, grid_u, grid_v, tangent_D);
187  /* Convert displacement to object space. */
188  mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
189 }
190 
192  const int ptex_face_index,
193  const int corner,
194  const int corner_delta,
195  int *r_other_ptex_face_index,
196  int *r_other_corner_index)
197 {
198  const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
199  const MPoly *poly = &data->mpoly[poly_corner->poly_index];
200  const int num_corners = poly->totloop;
201  const bool is_quad = (num_corners == 4);
202  const int poly_index = poly - data->mpoly;
203  const int start_ptex_face_index = data->face_ptex_offset[poly_index];
204  *r_other_corner_index = (corner + corner_delta + num_corners) % num_corners;
205  *r_other_ptex_face_index = is_quad ? start_ptex_face_index :
206  start_ptex_face_index + *r_other_corner_index;
207 }
208 
209 /* NOTE: Grid coordinates are relatiev to the other grid already. */
210 static void average_with_other(SubdivDisplacement *displacement,
211  const int ptex_face_index,
212  const int corner,
213  const float grid_u,
214  const float grid_v,
215  const int corner_delta,
216  float r_D[3])
217 {
218  MultiresDisplacementData *data = displacement->user_data;
219  const MDisps *other_displacement_grid = displacement_get_other_grid(
220  displacement, ptex_face_index, corner, corner_delta);
221  int other_ptex_face_index, other_corner_index;
223  data, ptex_face_index, corner, corner_delta, &other_ptex_face_index, &other_corner_index);
224  /* Get displacement in object space. */
225  float other_D[3];
227  other_displacement_grid,
228  grid_u,
229  grid_v,
230  other_ptex_face_index,
231  other_corner_index,
232  other_D);
233  /* Average result with the other displacement vector. */
234  add_v3_v3(r_D, other_D);
235  mul_v3_fl(r_D, 0.5f);
236 }
237 
238 static void average_with_all(SubdivDisplacement *displacement,
239  const int ptex_face_index,
240  const int corner,
241  const float UNUSED(grid_u),
242  const float UNUSED(grid_v),
243  float r_D[3])
244 {
245  MultiresDisplacementData *data = displacement->user_data;
246  const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
247  const MPoly *poly = &data->mpoly[poly_corner->poly_index];
248  const int num_corners = poly->totloop;
249  for (int corner_delta = 1; corner_delta < num_corners; corner_delta++) {
250  average_with_other(displacement, ptex_face_index, corner, 0.0f, 0.0f, corner_delta, r_D);
251  }
252 }
253 
254 static void average_with_next(SubdivDisplacement *displacement,
255  const int ptex_face_index,
256  const int corner,
257  const float grid_u,
258  const float UNUSED(grid_v),
259  float r_D[3])
260 {
261  average_with_other(displacement, ptex_face_index, corner, 0.0f, grid_u, 1, r_D);
262 }
263 
264 static void average_with_prev(SubdivDisplacement *displacement,
265  const int ptex_face_index,
266  const int corner,
267  const float UNUSED(grid_u),
268  const float grid_v,
269  float r_D[3])
270 {
271  average_with_other(displacement, ptex_face_index, corner, grid_v, 0.0f, -1, r_D);
272 }
273 
274 static void average_displacement(SubdivDisplacement *displacement,
275  eAverageWith average_with,
276  const int ptex_face_index,
277  const int corner,
278  const float grid_u,
279  const float grid_v,
280  float r_D[3])
281 {
282  switch (average_with) {
283  case AVERAGE_WITH_ALL:
284  average_with_all(displacement, ptex_face_index, corner, grid_u, grid_v, r_D);
285  break;
286  case AVERAGE_WITH_PREV:
287  average_with_prev(displacement, ptex_face_index, corner, grid_u, grid_v, r_D);
288  break;
289  case AVERAGE_WITH_NEXT:
290  average_with_next(displacement, ptex_face_index, corner, grid_u, grid_v, r_D);
291  break;
292  case AVERAGE_WITH_NONE:
293  break;
294  }
295 }
296 
298  const int ptex_face_index,
299  const float u,
300  const float v)
301 {
302  const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
303  const MPoly *poly = &data->mpoly[poly_corner->poly_index];
304  const int num_corners = poly->totloop;
305  const bool is_quad = (num_corners == 4);
306  if (is_quad) {
307  float dummy_corner_u, dummy_corner_v;
308  return BKE_subdiv_rotate_quad_to_corner(u, v, &dummy_corner_u, &dummy_corner_v);
309  }
310 
311  return poly_corner->corner;
312 }
313 
314 static void initialize(SubdivDisplacement *displacement)
315 {
316  MultiresDisplacementData *data = displacement->user_data;
318  data->is_initialized = true;
319 }
320 
321 static void eval_displacement(SubdivDisplacement *displacement,
322  const int ptex_face_index,
323  const float u,
324  const float v,
325  const float dPdu[3],
326  const float dPdv[3],
327  float r_D[3])
328 {
329  MultiresDisplacementData *data = displacement->user_data;
330  BLI_assert(data->is_initialized);
331  const int grid_size = data->grid_size;
332  /* Get displacement in tangent space. */
333  const MDisps *displacement_grid;
334  float grid_u, grid_v;
335  const int corner_of_quad = displacement_get_grid_and_coord(
336  displacement, ptex_face_index, u, v, &displacement_grid, &grid_u, &grid_v);
337  /* Read displacement from the current displacement grid and see if any
338  * averaging is needed. */
339  float tangent_D[3];
340  eAverageWith average_with = read_displacement_grid(
341  displacement_grid, grid_size, grid_u, grid_v, tangent_D);
342  /* Convert it to the object space. */
343  float tangent_matrix[3][3];
344  BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner_of_quad);
345  mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
346  /* For the boundary points of grid average two (or all) neighbor grids. */
347  const int corner = displacement_get_face_corner(data, ptex_face_index, u, v);
348  average_displacement(displacement, average_with, ptex_face_index, corner, grid_u, grid_v, r_D);
349 }
350 
351 static void free_displacement(SubdivDisplacement *displacement)
352 {
353  MultiresDisplacementData *data = displacement->user_data;
354  MEM_freeN(data->ptex_poly_corner);
355  MEM_freeN(data);
356 }
357 
358 /* TODO(sergey): This seems to be generally used information, which almost
359  * worth adding to a subdiv itself, with possible cache of the value. */
360 static int count_num_ptex_faces(const Mesh *mesh)
361 {
362  int num_ptex_faces = 0;
363  const MPoly *mpoly = mesh->mpoly;
364  for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
365  const MPoly *poly = &mpoly[poly_index];
366  num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
367  }
368  return num_ptex_faces;
369 }
370 
371 static void displacement_data_init_mapping(SubdivDisplacement *displacement, const Mesh *mesh)
372 {
373  MultiresDisplacementData *data = displacement->user_data;
374  const MPoly *mpoly = mesh->mpoly;
375  const int num_ptex_faces = count_num_ptex_faces(mesh);
376  /* Allocate memory. */
377  data->ptex_poly_corner = MEM_malloc_arrayN(
378  num_ptex_faces, sizeof(*data->ptex_poly_corner), "ptex poly corner");
379  /* Fill in offsets. */
380  int ptex_face_index = 0;
381  PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
382  for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
383  const MPoly *poly = &mpoly[poly_index];
384  if (poly->totloop == 4) {
385  ptex_poly_corner[ptex_face_index].poly_index = poly_index;
386  ptex_poly_corner[ptex_face_index].corner = 0;
387  ptex_face_index++;
388  }
389  else {
390  for (int corner = 0; corner < poly->totloop; corner++) {
391  ptex_poly_corner[ptex_face_index].poly_index = poly_index;
392  ptex_poly_corner[ptex_face_index].corner = corner;
393  ptex_face_index++;
394  }
395  }
396  }
397 }
398 
399 static void displacement_init_data(SubdivDisplacement *displacement,
400  Subdiv *subdiv,
401  Mesh *mesh,
402  const MultiresModifierData *mmd)
403 {
404  MultiresDisplacementData *data = displacement->user_data;
405  data->subdiv = subdiv;
406  data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
407  data->mesh = mesh;
408  data->mmd = mmd;
409  data->mpoly = mesh->mpoly;
411  data->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
412  data->is_initialized = false;
413  displacement_data_init_mapping(displacement, mesh);
414 }
415 
417 {
418  displacement->initialize = initialize;
419  displacement->eval_displacement = eval_displacement;
420  displacement->free = free_displacement;
421 }
422 
424  Mesh *mesh,
425  const MultiresModifierData *mmd)
426 {
427  /* Make sure we don't have previously assigned displacement. */
429  /* It is possible to have mesh without CD_MDISPS layer. Happens when using
430  * dynamic topology. */
432  return;
433  }
434  /* Allocate all required memory. */
435  SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement),
436  "multires displacement");
437  displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
438  "multires displacement data");
439  displacement_init_data(displacement, subdiv, mesh, mmd);
440  displacement_init_functions(displacement);
441  /* Finish. */
442  subdiv->displacement_evaluator = displacement;
443 }
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3], const float dPdu[3], const float dPdv[3], int corner)
void multiresModifier_ensure_external_read(struct Mesh *mesh, const struct MultiresModifierData *mmd)
BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(float ptex_u, float ptex_v, float *r_grid_u, float *r_grid_v)
Definition: subdiv_inline.h:15
BLI_INLINE int BKE_subdiv_grid_size_from_level(int level)
Definition: subdiv_inline.h:33
BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v)
Definition: subdiv_inline.h:68
BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(float grid_u, float grid_v, float *r_ptex_u, float *r_ptex_v)
Definition: subdiv_inline.h:24
int * BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
Definition: subdiv.c:209
BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(float quad_u, float quad_v, float *r_corner_u, float *r_corner_v)
Definition: subdiv_inline.h:38
void BKE_subdiv_displacement_detach(Subdiv *subdiv)
void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_dPdu[3], float r_dPdv[3])
Definition: subdiv_eval.c:286
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define UNUSED(x)
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 y
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
float(* disps)[3]
int totpoly
struct MPoly * mpoly
CustomData ldata
const MultiresModifierData * mmd
void(* initialize)(struct SubdivDisplacement *displacement)
Definition: BKE_subdiv.h:125
void(* eval_displacement)(struct SubdivDisplacement *displacement, int ptex_face_index, float u, float v, const float dPdu[3], const float dPdv[3], float r_D[3])
Definition: BKE_subdiv.h:137
void(* free)(struct SubdivDisplacement *displacement)
Definition: BKE_subdiv.h:146
struct SubdivDisplacement * displacement_evaluator
Definition: BKE_subdiv.h:168
static void average_read_displacement_object(MultiresDisplacementData *data, const MDisps *displacement_grid, const float grid_u, const float grid_v, const int ptex_face_index, const int corner_index, float r_D[3])
void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv, Mesh *mesh, const MultiresModifierData *mmd)
static void displacement_data_init_mapping(SubdivDisplacement *displacement, const Mesh *mesh)
static const MDisps * displacement_get_other_grid(SubdivDisplacement *displacement, const int ptex_face_index, const int corner, const int corner_delta)
static void average_read_displacement_tangent(MultiresDisplacementData *data, const MDisps *other_displacement_grid, const float grid_u, const float grid_v, float r_tangent_D[3])
static int displacement_get_grid_and_coord(SubdivDisplacement *displacement, const int ptex_face_index, const float u, const float v, const MDisps **r_displacement_grid, float *grid_u, float *grid_v)
static void average_with_other(SubdivDisplacement *displacement, const int ptex_face_index, const int corner, const float grid_u, const float grid_v, const int corner_delta, float r_D[3])
static void average_displacement(SubdivDisplacement *displacement, eAverageWith average_with, const int ptex_face_index, const int corner, const float grid_u, const float grid_v, float r_D[3])
static void displacement_init_functions(SubdivDisplacement *displacement)
static void average_with_next(SubdivDisplacement *displacement, const int ptex_face_index, const int corner, const float grid_u, const float UNUSED(grid_v), float r_D[3])
static int count_num_ptex_faces(const Mesh *mesh)
static void free_displacement(SubdivDisplacement *displacement)
static void average_construct_tangent_matrix(Subdiv *subdiv, const MPoly *poly, const int ptex_face_index, const int corner, const float u, const float v, float r_tangent_matrix[3][3])
static void average_get_other_ptex_and_corner(MultiresDisplacementData *data, const int ptex_face_index, const int corner, const int corner_delta, int *r_other_ptex_face_index, int *r_other_corner_index)
static void average_with_all(SubdivDisplacement *displacement, const int ptex_face_index, const int corner, const float UNUSED(grid_u), const float UNUSED(grid_v), float r_D[3])
struct MultiresDisplacementData MultiresDisplacementData
static int displacement_get_face_corner(MultiresDisplacementData *data, const int ptex_face_index, const float u, const float v)
static void initialize(SubdivDisplacement *displacement)
static void average_convert_grid_coord_to_ptex(const MPoly *poly, const int corner, const float grid_u, const float grid_v, float *r_ptex_face_u, float *r_ptex_face_v)
struct PolyCornerIndex PolyCornerIndex
static void average_with_prev(SubdivDisplacement *displacement, const int ptex_face_index, const int corner, const float UNUSED(grid_u), const float grid_v, float r_D[3])
static void displacement_init_data(SubdivDisplacement *displacement, Subdiv *subdiv, Mesh *mesh, const MultiresModifierData *mmd)
static void eval_displacement(SubdivDisplacement *displacement, const int ptex_face_index, const float u, const float v, const float dPdu[3], const float dPdv[3], float r_D[3])
BLI_INLINE eAverageWith read_displacement_grid(const MDisps *displacement_grid, const int grid_size, const float grid_u, const float grid_v, float r_tangent_D[3])