Blender V4.5
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 float dummy_P[3], dPdu[3], dPdv[3], D[3];
76 eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
77 /* Accumulate displacement if needed. */
78 if (ctx->have_displacement) {
79 eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
80 /* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily
81 * initialized to zeroes. */
82 if (ctx->accumulated_counters[vertex_index] == 0) {
83 copy_v3_v3(ctx->vert_positions[vertex_index], D);
84 }
85 else {
86 add_v3_v3(ctx->vert_positions[vertex_index], D);
87 }
88 }
89 ++ctx->accumulated_counters[vertex_index];
90}
91
93
94/* -------------------------------------------------------------------- */
97
98static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context,
99 const int /*num_vertices*/,
100 const int /*num_edges*/,
101 const int /*num_loops*/,
102 const int /*num_faces*/,
103 const int * /*subdiv_face_offset*/)
104{
105 SubdivDeformContext *subdiv_context = static_cast<SubdivDeformContext *>(
106 foreach_context->user_data);
107 subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->verts_num);
108 return true;
109}
110
111static void subdiv_mesh_vertex_every_corner(const ForeachContext *foreach_context,
112 void * /*tls*/,
113 const int ptex_face_index,
114 const float u,
115 const float v,
116 const int coarse_vertex_index,
117 const int /*coarse_face_index*/,
118 const int /*coarse_corner*/,
119 const int /*subdiv_vertex_index*/)
120{
121 SubdivDeformContext *ctx = static_cast<SubdivDeformContext *>(foreach_context->user_data);
122 subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index);
123}
124
125static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
126 void * /*tls*/,
127 const int ptex_face_index,
128 const float u,
129 const float v,
130 const int coarse_vertex_index,
131 const int /*coarse_face_index*/,
132 const int /*coarse_corner*/,
133 const int /*subdiv_vertex_index*/)
134{
135 SubdivDeformContext *ctx = static_cast<SubdivDeformContext *>(foreach_context->user_data);
136 float inv_num_accumulated = 1.0f;
137 if (ctx->accumulated_counters != nullptr) {
138 inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index];
139 }
140 /* Displacement is accumulated in subdiv vertex position.
141 * Needs to be backed up before copying data from original vertex. */
142 float D[3] = {0.0f, 0.0f, 0.0f};
143 float *vertex_co = ctx->vert_positions[coarse_vertex_index];
144 if (ctx->have_displacement) {
145 copy_v3_v3(D, vertex_co);
146 mul_v3_fl(D, inv_num_accumulated);
147 }
148 /* Copy custom data and evaluate position. */
149 eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
150 /* Apply displacement. */
151 add_v3_v3(vertex_co, D);
152}
153
155
156/* -------------------------------------------------------------------- */
159
160static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
161 ForeachContext *foreach_context)
162{
163 memset(foreach_context, 0, sizeof(*foreach_context));
164 /* General information. */
165 foreach_context->topology_info = subdiv_mesh_topology_info;
166 /* Every boundary geometry. Used for displacement and normals averaging. */
167 if (subdiv_context->have_displacement) {
169 }
170 foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
171}
172
174
175/* -------------------------------------------------------------------- */
178
180 const Mesh *coarse_mesh,
181 MutableSpan<float3> vert_positions)
182{
184 /* Make sure evaluator is up to date with possible new topology, and that
185 * is refined for the new positions of coarse vertices. */
187 subdiv, coarse_mesh, vert_positions, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
188 {
189 /* This could happen in two situations:
190 * - OpenSubdiv is disabled.
191 * - Something totally bad happened, and OpenSubdiv rejected our
192 * topology.
193 * In either way, we can't safely continue. */
194 if (coarse_mesh->faces_num) {
196 return;
197 }
198 }
199
200 /* Initialize subdivision mesh creation context. */
201 SubdivDeformContext subdiv_context = {nullptr};
202 subdiv_context.coarse_mesh = coarse_mesh;
203 subdiv_context.subdiv = subdiv;
204 subdiv_context.vert_positions = vert_positions;
205 subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
206
207 ForeachContext foreach_context;
208 setup_foreach_callbacks(&subdiv_context, &foreach_context);
209 foreach_context.user_data = &subdiv_context;
210
211 /* Dummy mesh rasterization settings. */
212 ToMeshSettings mesh_settings;
213 mesh_settings.resolution = 1;
214 mesh_settings.use_optimal_display = false;
215
216 /* Multi-threaded traversal/evaluation. */
218 foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
220
221 // BKE_mesh_validate(result, true, true);
223
224 /* Free used memory. */
225 subdiv_mesh_context_free(&subdiv_context);
226}
227
229
230} // 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.
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define MEM_SAFE_FREE(v)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
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