Blender V4.3
subdiv_deform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstring>
12
13#include "DNA_mesh_types.h"
14
15#include "BLI_math_vector.h"
16#include "BLI_utildefines.h"
17
18#include "BKE_customdata.hh"
19#include "BKE_subdiv.hh"
20#include "BKE_subdiv_eval.hh"
21#include "BKE_subdiv_foreach.hh"
22#include "BKE_subdiv_mesh.hh"
23
24#include "MEM_guardedalloc.h"
25
26namespace blender::bke::subdiv {
27
28/* -------------------------------------------------------------------- */
35
37
38 /* Accumulated values.
39 *
40 * Averaging is happening for vertices which correspond to the coarse ones.
41 * This is needed for displacement.
42 *
43 * Displacement is being accumulated to a vertices coordinates, since those
44 * are not needed during traversal of face-vertices vertices. */
45 /* Per-subdivided vertex counter of averaged values. */
47
49};
50
51static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
52{
53 if (!ctx->have_displacement) {
54 return;
55 }
56 ctx->accumulated_counters = static_cast<int *>(
57 MEM_calloc_arrayN(num_vertices, sizeof(*ctx->accumulated_counters), __func__));
58}
59
64
67/* -------------------------------------------------------------------- */
72 const int ptex_face_index,
73 const float u,
74 const float v,
75 int vertex_index)
76{
77 Subdiv *subdiv = ctx->subdiv;
78 float dummy_P[3], dPdu[3], dPdv[3], D[3];
79 eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
80 /* Accumulate displacement if needed. */
81 if (ctx->have_displacement) {
82 eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
83 /* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily
84 * initialized to zeroes. */
85 if (ctx->accumulated_counters[vertex_index] == 0) {
86 copy_v3_v3(ctx->vert_positions[vertex_index], D);
87 }
88 else {
89 add_v3_v3(ctx->vert_positions[vertex_index], D);
90 }
91 }
92 ++ctx->accumulated_counters[vertex_index];
93}
94
97/* -------------------------------------------------------------------- */
101static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context,
102 const int /*num_vertices*/,
103 const int /*num_edges*/,
104 const int /*num_loops*/,
105 const int /*num_faces*/,
106 const int * /*subdiv_face_offset*/)
107{
108 SubdivDeformContext *subdiv_context = static_cast<SubdivDeformContext *>(
109 foreach_context->user_data);
110 subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->verts_num);
111 return true;
112}
113
114static void subdiv_mesh_vertex_every_corner(const ForeachContext *foreach_context,
115 void * /*tls*/,
116 const int ptex_face_index,
117 const float u,
118 const float v,
119 const int coarse_vertex_index,
120 const int /*coarse_face_index*/,
121 const int /*coarse_corner*/,
122 const int /*subdiv_vertex_index*/)
123{
124 SubdivDeformContext *ctx = static_cast<SubdivDeformContext *>(foreach_context->user_data);
125 subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index);
126}
127
128static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
129 void * /*tls*/,
130 const int ptex_face_index,
131 const float u,
132 const float v,
133 const int coarse_vertex_index,
134 const int /*coarse_face_index*/,
135 const int /*coarse_corner*/,
136 const int /*subdiv_vertex_index*/)
137{
138 SubdivDeformContext *ctx = static_cast<SubdivDeformContext *>(foreach_context->user_data);
139 BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
140 float inv_num_accumulated = 1.0f;
141 if (ctx->accumulated_counters != nullptr) {
142 inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index];
143 }
144 /* Displacement is accumulated in subdiv vertex position.
145 * Needs to be backed up before copying data from original vertex. */
146 float D[3] = {0.0f, 0.0f, 0.0f};
147 float *vertex_co = ctx->vert_positions[coarse_vertex_index];
148 if (ctx->have_displacement) {
149 copy_v3_v3(D, vertex_co);
150 mul_v3_fl(D, inv_num_accumulated);
151 }
152 /* Copy custom data and evaluate position. */
153 eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
154 /* Apply displacement. */
155 add_v3_v3(vertex_co, D);
156}
157
160/* -------------------------------------------------------------------- */
164static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
165 ForeachContext *foreach_context)
166{
167 memset(foreach_context, 0, sizeof(*foreach_context));
168 /* General information. */
169 foreach_context->topology_info = subdiv_mesh_topology_info;
170 /* Every boundary geometry. Used for displacement and normals averaging. */
171 if (subdiv_context->have_displacement) {
173 }
174 foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
175}
176
179/* -------------------------------------------------------------------- */
184 const Mesh *coarse_mesh,
185 MutableSpan<float3> vert_positions)
186{
188 /* Make sure evaluator is up to date with possible new topology, and that
189 * is refined for the new positions of coarse vertices. */
191 subdiv, coarse_mesh, vert_positions, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
192 {
193 /* This could happen in two situations:
194 * - OpenSubdiv is disabled.
195 * - Something totally bad happened, and OpenSubdiv rejected our
196 * topology.
197 * In either way, we can't safely continue. */
198 if (coarse_mesh->faces_num) {
200 return;
201 }
202 }
203
204 /* Initialize subdivision mesh creation context. */
205 SubdivDeformContext subdiv_context = {nullptr};
206 subdiv_context.coarse_mesh = coarse_mesh;
207 subdiv_context.subdiv = subdiv;
208 subdiv_context.vert_positions = vert_positions;
209 subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
210
211 ForeachContext foreach_context;
212 setup_foreach_callbacks(&subdiv_context, &foreach_context);
213 foreach_context.user_data = &subdiv_context;
214
215 /* Dummy mesh rasterization settings. */
216 ToMeshSettings mesh_settings;
217 mesh_settings.resolution = 1;
218 mesh_settings.use_optimal_display = false;
219
220 /* Multi-threaded traversal/evaluation. */
222 foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
224
225 // BKE_mesh_validate(result, true, true);
227
228 /* Free used memory. */
229 subdiv_mesh_context_free(&subdiv_context);
230}
231
234} // namespace blender::bke::subdiv
CustomData interface, see also DNA_customdata_types.h.
#define ORIGINDEX_NONE
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
bool foreach_subdiv_geometry(Subdiv *subdiv, const ForeachContext *context, const ToMeshSettings *mesh_settings, const Mesh *coarse_mesh)
bool eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, Span< float3 > coarse_vert_positions, eSubdivEvaluatorType evaluator_type, OpenSubdiv_EvaluatorCache *evaluator_cache)
void eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3])
void eval_displacement(Subdiv *subdiv, int ptex_face_index, float u, float v, const float dPdu[3], const float dPdv[3], float r_D[3])
void eval_limit_point_and_derivatives(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_dPdu[3], float r_dPdv[3])
void deform_coarse_vertices(Subdiv *subdiv, const Mesh *coarse_mesh, MutableSpan< float3 > vert_positions)
static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, ForeachContext *foreach_context)
static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
void stats_begin(SubdivStats *stats, StatsValue value)
void stats_end(SubdivStats *stats, StatsValue value)
static void subdiv_mesh_vertex_every_corner(const ForeachContext *foreach_context, void *, const int ptex_face_index, const float u, const float v, const int coarse_vertex_index, const int, const int, const int)
static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context, void *, const int ptex_face_index, const float u, const float v, const int coarse_vertex_index, const int, const int, const int)
static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, const int ptex_face_index, const float u, const float v, int vertex_index)
static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context, const int, const int, const int, const int, const int *)
static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
int faces_num
int verts_num
ForeachTopologyInformationCb topology_info
ForeachVertexFromCornerCb vertex_every_corner
Displacement * displacement_evaluator