Blender V5.0
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
8
10
11#include <cstring>
12
13#include "DNA_mesh_types.h"
14
15#include "BLI_math_vector.h"
16
17#include "BKE_subdiv.hh"
18#include "BKE_subdiv_eval.hh"
19#include "BKE_subdiv_foreach.hh"
20#include "BKE_subdiv_mesh.hh"
21
22#include "MEM_guardedalloc.h"
23
24namespace blender::bke::subdiv {
25
26/* -------------------------------------------------------------------- */
29
33
35
36 /* Accumulated values.
37 *
38 * Averaging is happening for vertices which correspond to the coarse ones.
39 * This is needed for displacement.
40 *
41 * Displacement is being accumulated to a vertices coordinates, since those
42 * are not needed during traversal of face-vertices vertices. */
43 /* Per-subdivided vertex counter of averaged values. */
45
47};
48
49static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
50{
51 if (!ctx->have_displacement) {
52 return;
53 }
54 ctx->accumulated_counters = MEM_calloc_arrayN<int>(num_vertices, __func__);
55}
56
61
63
64/* -------------------------------------------------------------------- */
67
69 const int ptex_face_index,
70 const float u,
71 const float v,
72 int vertex_index)
73{
74 Subdiv *subdiv = ctx->subdiv;
75 float3 dummy_P;
76 float3 dPdu;
77 float3 dPdv;
78 float3 D;
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
96
97/* -------------------------------------------------------------------- */
100
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 float inv_num_accumulated = 1.0f;
140 if (ctx->accumulated_counters != nullptr) {
141 inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index];
142 }
143 /* Displacement is accumulated in subdiv vertex position.
144 * Needs to be backed up before copying data from original vertex. */
145 float D[3] = {0.0f, 0.0f, 0.0f};
146 float3 &vertex_co = ctx->vert_positions[coarse_vertex_index];
147 if (ctx->have_displacement) {
148 copy_v3_v3(D, vertex_co);
149 mul_v3_fl(D, inv_num_accumulated);
150 }
151 /* Copy custom data and evaluate position. */
152 vertex_co = eval_limit_point(ctx->subdiv, ptex_face_index, u, v);
153 /* Apply displacement. */
154 add_v3_v3(vertex_co, D);
155}
156
158
159/* -------------------------------------------------------------------- */
162
163static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
164 ForeachContext *foreach_context)
165{
166 *foreach_context = {};
167 /* General information. */
168 foreach_context->topology_info = subdiv_mesh_topology_info;
169 /* Every boundary geometry. Used for displacement and normals averaging. */
170 if (subdiv_context->have_displacement) {
172 }
173 foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
174}
175
177
178/* -------------------------------------------------------------------- */
181
183 const Mesh *coarse_mesh,
184 MutableSpan<float3> vert_positions)
185{
187 /* Make sure evaluator is up to date with possible new topology, and that
188 * is refined for the new positions of coarse vertices. */
189 if (!eval_begin_from_mesh(subdiv, coarse_mesh, SUBDIV_EVALUATOR_TYPE_CPU, vert_positions)) {
190 /* This could happen in two situations:
191 * - OpenSubdiv is disabled.
192 * - Something totally bad happened, and OpenSubdiv rejected our
193 * topology.
194 * In either way, we can't safely continue. */
195 if (coarse_mesh->faces_num) {
197 return;
198 }
199 }
200
201 /* Initialize subdivision mesh creation context. */
202 SubdivDeformContext subdiv_context = {nullptr};
203 subdiv_context.coarse_mesh = coarse_mesh;
204 subdiv_context.subdiv = subdiv;
205 subdiv_context.vert_positions = vert_positions;
206 subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
207
208 ForeachContext foreach_context;
209 setup_foreach_callbacks(&subdiv_context, &foreach_context);
210 foreach_context.user_data = &subdiv_context;
211
212 /* Dummy mesh rasterization settings. */
213 ToMeshSettings mesh_settings;
214 mesh_settings.resolution = 1;
215 mesh_settings.use_optimal_display = false;
216
217 /* Multi-threaded traversal/evaluation. */
219 foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
221
222 // BKE_mesh_validate(result, true, true);
224
225 /* Free used memory. */
226 subdiv_mesh_context_free(&subdiv_context);
227}
228
230
231} // namespace blender::bke::subdiv
#define D
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:123
bool eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, eSubdivEvaluatorType evaluator_type, Span< float3 > coarse_vert_positions={}, OpenSubdiv_EvaluatorCache *evaluator_cache=nullptr)
float3 eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v)
bool foreach_subdiv_geometry(Subdiv *subdiv, const ForeachContext *context, const ToMeshSettings *mesh_settings, const Mesh *coarse_mesh)
void deform_coarse_vertices(Subdiv *subdiv, const Mesh *coarse_mesh, MutableSpan< float3 > vert_positions)
void eval_limit_point_and_derivatives(Subdiv *subdiv, int ptex_face_index, float u, float v, float3 &r_P, float3 &r_dPdu, float3 &r_dPdv)
static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, ForeachContext *foreach_context)
static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
void eval_displacement(Subdiv *subdiv, int ptex_face_index, float u, float v, const float3 &dPdu, const float3 &dPdv, float3 &r_D)
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)
VecBase< float, 3 > float3
int faces_num
int verts_num
ForeachTopologyInformationCb topology_info
ForeachVertexFromCornerCb vertex_every_corner