Refactor: Simplify subdiv utilities

- Return evaluated points as function return value.
  Used in cases when only limit or final point is requested, without
  partial derivatives.

- Re-order function argument list and use default argument values to
  simplify usage in the simple/typical cases.

No functional changes expected.
This commit is contained in:
Sergey Sharybin
2025-08-15 16:30:21 +02:00
parent e24e58f293
commit 1e4764a9a5
12 changed files with 51 additions and 61 deletions

View File

@@ -278,9 +278,8 @@ inline int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG &subdiv_ccg, const
return subdiv_ccg.grid_to_face_map[grid_index];
}
void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord,
blender::float3 &r_point);
blender::float3 BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord);
void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
int grid_index,

View File

@@ -35,9 +35,9 @@ bool eval_begin(Subdiv *subdiv,
*/
bool eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
Span<float3> coarse_vert_positions,
eSubdivEvaluatorType evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache);
Span<float3> coarse_vert_positions = {},
OpenSubdiv_EvaluatorCache *evaluator_cache = nullptr);
bool eval_refine_from_mesh(Subdiv *subdiv, const Mesh *mesh, Span<float3> coarse_vert_positions);
/* Makes sure displacement evaluator is initialized.
@@ -50,7 +50,7 @@ void eval_init_displacement(Subdiv *subdiv);
/* Evaluate point at a limit surface, with optional derivatives and normal. */
void eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float3 &r_P);
float3 eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v);
void eval_limit_point_and_derivatives(Subdiv *subdiv,
int ptex_face_index,
float u,
@@ -88,6 +88,6 @@ void eval_displacement(Subdiv *subdiv,
float3 &r_D);
/* Evaluate point on a limit surface with displacement applied to it. */
void eval_final_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float3 &r_P);
float3 eval_final_point(Subdiv *subdiv, int ptex_face_index, float u, float v);
} // namespace blender::bke::subdiv

View File

@@ -98,48 +98,48 @@ struct ForeachContext {
*
* NOTE: If this callback returns false, the foreach loop is aborted.
*/
ForeachTopologyInformationCb topology_info;
ForeachTopologyInformationCb topology_info = nullptr;
/* These callbacks are called from every ptex which shares "emitting"
* vertex or edge.
*/
ForeachVertexFromCornerCb vertex_every_corner;
ForeachVertexFromEdgeCb vertex_every_edge;
ForeachVertexFromCornerCb vertex_every_corner = nullptr;
ForeachVertexFromEdgeCb vertex_every_edge = nullptr;
/* Those callbacks are run once per subdivision vertex, ptex is undefined
* as in it will be whatever first ptex face happened to be traversed in
* the multi-threaded environment and which shares "emitting" vertex or
* edge.
*/
ForeachVertexFromCornerCb vertex_corner;
ForeachVertexFromEdgeCb vertex_edge;
ForeachVertexFromCornerCb vertex_corner = nullptr;
ForeachVertexFromEdgeCb vertex_edge = nullptr;
/* Called exactly once, always corresponds to a single ptex face. */
ForeachVertexInnerCb vertex_inner;
ForeachVertexInnerCb vertex_inner = nullptr;
/* Called once for each loose vertex. One loose coarse vertex corresponds
* to a single subdivision vertex.
*/
ForeachLooseCb vertex_loose;
ForeachLooseCb vertex_loose = nullptr;
/* Called once per vertex created for loose edge. */
ForeachVertexOfLooseEdgeCb vertex_of_loose_edge;
ForeachVertexOfLooseEdgeCb vertex_of_loose_edge = nullptr;
/* NOTE: If subdivided edge does not come from coarse edge, ORIGINDEX_NONE
* will be passed as coarse_edge_index.
*/
ForeachEdgeCb edge;
ForeachEdgeCb edge = nullptr;
/* NOTE: If subdivided loop does not come from coarse loop, ORIGINDEX_NONE
* will be passed as coarse_loop_index.
*/
ForeachLoopCb loop;
ForeachPolygonCb poly;
ForeachLoopCb loop = nullptr;
ForeachPolygonCb poly = nullptr;
/* User-defined pointer, to allow callbacks know something about context the
* traversal is happening for.
*/
void *user_data;
void *user_data = nullptr;
/* Initial value of TLS data. */
void *user_data_tls;
void *user_data_tls = nullptr;
/* Size of TLS data. */
size_t user_data_tls_size;
size_t user_data_tls_size = 0;
/* Function to free TLS storage. */
void (*user_data_tls_free)(void *tls);
void (*user_data_tls_free)(void *tls) = nullptr;
};
/* Invokes callbacks in the order and with values which corresponds to creation

View File

@@ -25,9 +25,9 @@ struct ToMeshSettings {
* created for a corner of non-quad face) will have resolution of
* `resolution - 1`.
*/
int resolution;
int resolution = -1;
/** When true, only edges emitted from coarse ones will be displayed. */
bool use_optimal_display;
bool use_optimal_display = false;
};
/** Create real hi-res mesh from subdivision, all geometry is "real". */

View File

@@ -1319,9 +1319,8 @@ static void evaluate_higher_grid_positions(MultiresReshapeSmoothContext *reshape
reshape_context, grid_coord);
/* Surface. */
blender::float3 P;
blender::bke::subdiv::eval_limit_point(
reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
const blender::float3 P = blender::bke::subdiv::eval_limit_point(
reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v);
*grid_element.displacement = P;

View File

@@ -56,9 +56,7 @@ blender::bke::subdiv::Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgrap
if (!subdiv) {
return nullptr;
}
if (!subdiv::eval_begin_from_mesh(
subdiv, base_mesh, {}, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
{
if (!subdiv::eval_begin_from_mesh(subdiv, base_mesh, subdiv::SUBDIV_EVALUATOR_TYPE_CPU)) {
subdiv::free(subdiv);
return nullptr;
}

View File

@@ -48,9 +48,7 @@ static blender::bke::subdiv::Subdiv *subdiv_for_simple_to_catmull_clark(Object *
subdiv::Subdiv *subdiv = subdiv::new_from_converter(&subdiv_settings, &converter);
subdiv::converter_free(&converter);
if (!subdiv::eval_begin_from_mesh(
subdiv, base_mesh, {}, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
{
if (!subdiv::eval_begin_from_mesh(subdiv, base_mesh, subdiv::SUBDIV_EVALUATOR_TYPE_CPU)) {
subdiv::free(subdiv);
return nullptr;
}

View File

@@ -109,7 +109,7 @@ static void subdiv_ccg_eval_grid_element_limit(Subdiv &subdiv,
const int element)
{
if (subdiv.displacement_evaluator != nullptr) {
eval_final_point(&subdiv, ptex_face_index, u, v, subdiv_ccg.positions[element]);
subdiv_ccg.positions[element] = eval_final_point(&subdiv, ptex_face_index, u, v);
}
else if (!subdiv_ccg.normals.is_empty()) {
eval_limit_point_and_normal(&subdiv,
@@ -120,7 +120,7 @@ static void subdiv_ccg_eval_grid_element_limit(Subdiv &subdiv,
subdiv_ccg.normals[element]);
}
else {
eval_limit_point(&subdiv, ptex_face_index, u, v, subdiv_ccg.positions[element]);
subdiv_ccg.positions[element] = eval_limit_point(&subdiv, ptex_face_index, u, v);
}
}
@@ -416,7 +416,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv,
{
/* Make sure evaluator is ready. */
stats_begin(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
if (!eval_begin_from_mesh(&subdiv, &coarse_mesh, {}, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
if (!eval_begin_from_mesh(&subdiv, &coarse_mesh, SUBDIV_EVALUATOR_TYPE_CPU)) {
if (coarse_mesh.faces_num) {
return nullptr;
}
@@ -1600,15 +1600,13 @@ static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG &subdiv_ccg,
}
}
void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord,
float3 &r_point)
float3 BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
{
Subdiv *subdiv = subdiv_ccg.subdiv;
int ptex_face_index;
float u, v;
subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, ptex_face_index, u, v);
eval_limit_point(subdiv, ptex_face_index, u, v, r_point);
return eval_limit_point(subdiv, ptex_face_index, u, v);
}
void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg,
@@ -1623,7 +1621,7 @@ void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg,
const int i = CCG_grid_xy_to_index(key.grid_size, x, y);
coord.x = x;
coord.y = y;
BKE_subdiv_ccg_eval_limit_point(subdiv_ccg, coord, r_limit_positions[i]);
r_limit_positions[i] = BKE_subdiv_ccg_eval_limit_point(subdiv_ccg, coord);
}
}
}

View File

@@ -149,7 +149,7 @@ static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
mul_v3_fl(D, inv_num_accumulated);
}
/* Copy custom data and evaluate position. */
eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
vertex_co = eval_limit_point(ctx->subdiv, ptex_face_index, u, v);
/* Apply displacement. */
add_v3_v3(vertex_co, D);
}
@@ -186,9 +186,7 @@ void deform_coarse_vertices(Subdiv *subdiv,
stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is refined for the new positions of coarse vertices. */
if (!eval_begin_from_mesh(
subdiv, coarse_mesh, vert_positions, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
{
if (!eval_begin_from_mesh(subdiv, coarse_mesh, SUBDIV_EVALUATOR_TYPE_CPU, vert_positions)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our

View File

@@ -220,8 +220,8 @@ static void get_mesh_evaluator_settings(OpenSubdiv_EvaluatorSettings *settings,
bool eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
const Span<float3> coarse_vert_positions,
eSubdivEvaluatorType evaluator_type,
const Span<float3> coarse_vert_positions,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
#ifdef WITH_OPENSUBDIV
@@ -288,13 +288,15 @@ void eval_init_displacement(Subdiv *subdiv)
* Single point queries.
*/
void eval_limit_point(
Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float3 &r_P)
float3 eval_limit_point(Subdiv *subdiv, const int ptex_face_index, const float u, const float v)
{
#ifdef WITH_OPENSUBDIV
float3 r_P;
subdiv->evaluator->eval_output->evaluateLimit(ptex_face_index, u, v, r_P, nullptr, nullptr);
return r_P;
#else
UNUSED_VARS(subdiv, ptex_face_index, u, v, r_P);
return {0.0f, 0.0f, 0.0f};
#endif
}
@@ -383,9 +385,9 @@ void eval_displacement(Subdiv *subdiv,
subdiv->displacement_evaluator, ptex_face_index, u, v, dPdu, dPdv, r_D);
}
void eval_final_point(
Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float3 &r_P)
float3 eval_final_point(Subdiv *subdiv, const int ptex_face_index, const float u, const float v)
{
float3 r_P;
if (subdiv->displacement_evaluator) {
float3 dPdu;
float3 dPdv;
@@ -395,8 +397,9 @@ void eval_final_point(
r_P += D;
}
else {
eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
r_P = eval_limit_point(subdiv, ptex_face_index, u, v);
}
return r_P;
}
} // namespace blender::bke::subdiv

View File

@@ -644,7 +644,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
}
/* Copy custom data and evaluate position. */
subdiv_vertex_data_copy(ctx, coarse_vertex_index, subdiv_vertex_index);
eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
subdiv_position = eval_limit_point(ctx->subdiv, ptex_face_index, u, v);
/* Apply displacement. */
subdiv_position += D;
/* Evaluate undeformed texture coordinate. */
@@ -672,7 +672,7 @@ static void evaluate_vertex_and_apply_displacement_interpolate(
}
/* Interpolate custom data and evaluate position. */
subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, vertex_interpolation, u, v);
eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
subdiv_position = eval_limit_point(ctx->subdiv, ptex_face_index, u, v);
/* Apply displacement. */
add_v3_v3(subdiv_position, D);
/* Evaluate undeformed texture coordinate. */
@@ -825,10 +825,9 @@ static void subdiv_mesh_vertex_inner(const ForeachContext *foreach_context,
Subdiv *subdiv = ctx->subdiv;
const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
Mesh *subdiv_mesh = ctx->subdiv_mesh;
float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_face_index, coarse_corner);
subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, &tls->vertex_interpolation, u, v);
eval_final_point(subdiv, ptex_face_index, u, v, subdiv_position);
ctx->subdiv_positions[subdiv_vertex_index] = eval_final_point(subdiv, ptex_face_index, u, v);
subdiv_mesh_tag_center_vertex(coarse_face, subdiv_vertex_index, u, v, subdiv_mesh);
subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
}
@@ -1158,11 +1157,10 @@ Mesh *subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh
stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* it is refined for the new positions of coarse vertices. */
if (!eval_begin_from_mesh(subdiv, coarse_mesh, {}, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
if (!eval_begin_from_mesh(subdiv, coarse_mesh, SUBDIV_EVALUATOR_TYPE_CPU)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
* topology.
* - Something totally bad happened, and OpenSubdiv rejected our topology.
* In either way, we can't safely continue. */
if (coarse_mesh->faces_num) {
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);

View File

@@ -1628,12 +1628,11 @@ static bool draw_subdiv_create_requested_buffers(Object &ob,
};
if (!bke::subdiv::eval_begin_from_mesh(
subdiv, mesh_eval, {}, bke::subdiv::SUBDIV_EVALUATOR_TYPE_GPU, g_subdiv_evaluator_cache))
subdiv, mesh_eval, bke::subdiv::SUBDIV_EVALUATOR_TYPE_GPU))
{
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
* topology.
* - Something totally bad happened, and OpenSubdiv rejected our topology.
* In either way, we can't safely continue. However, we still have to handle potential loose
* geometry, which is done separately. */
if (mesh_eval->faces_num) {