Cleanup: use doxygen comments for BKE_subdiv*

This commit is contained in:
Campbell Barton
2025-08-24 16:19:48 +10:00
parent 1e2476f362
commit a080a2f4d0
6 changed files with 271 additions and 172 deletions

View File

@@ -22,11 +22,11 @@ class TopologyRefinerImpl;
namespace blender::bke::subdiv {
enum VtxBoundaryInterpolation {
/* Do not interpolate boundaries. */
/** Do not interpolate boundaries. */
SUBDIV_VTX_BOUNDARY_NONE,
/* Sharpen edges. */
/** Sharpen edges. */
SUBDIV_VTX_BOUNDARY_EDGE_ONLY,
/* sharpen edges and corners, */
/** Sharpen edges and corners. */
SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER,
};
@@ -40,14 +40,17 @@ enum FVarLinearInterpolation {
};
struct Settings {
/* Simple subdivision corresponds to "Simple" option in the interface. When it's enabled, the
/**
* Simple subdivision corresponds to "Simple" option in the interface. When it's enabled, the
* subdivided mesh is not "smoothed": new vertices are added uniformly on the existing surface.
*
* On an OpenSubdiv implementation level this translates to a subdivision scheme:
* when is_simple is true OSD_SCHEME_BILINEAR is used, otherwise OSD_SCHEME_CATMARK. */
* when is_simple is true OSD_SCHEME_BILINEAR is used, otherwise OSD_SCHEME_CATMARK.
*/
bool is_simple;
/* This refers to an adaptive isolation when creating patches for the subdivided surface.
/**
* This refers to an adaptive isolation when creating patches for the subdivided surface.
*
* When is set to false (aka uniform subdivision) fixed depth of isolation is used, which
* allows to iteratively add more subdivisions (uniform subdivision level 2 = uniform subdivision
@@ -56,13 +59,16 @@ struct Settings {
*
* Adaptive isolation generates patches at a limit surface (aka as if infinite number of uniform
* subdivisions have been applied). This setting allows to have matches normal and tangent space
* the same independent of number of subdivisions set in modifier settings. */
* the same independent of number of subdivisions set in modifier settings.
*/
bool is_adaptive;
/* Corresponds to Quality option in modifier settings: higher values means the final surface
/**
* Corresponds to Quality option in modifier settings: higher values means the final surface
* will be more accurately represented by patches.
*
* On an OpenSubdiv implementation level this is an isolation level. */
* On an OpenSubdiv implementation level this is an isolation level.
*/
int level;
bool use_creases;
@@ -71,7 +77,9 @@ struct Settings {
FVarLinearInterpolation fvar_linear_interpolation;
};
/* NOTE: Order of enumerators MUST match order of values in SubdivStats. */
/**
* \note Order of enumerators MUST match order of values in SubdivStats.
*/
enum StatsValue {
SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0,
SUBDIV_STATS_SUBDIV_TO_MESH,
@@ -88,52 +96,60 @@ enum StatsValue {
struct SubdivStats {
union {
struct {
/* Time spent on creating topology refiner, which includes time
/**
* Time spent on creating topology refiner, which includes time
* spend on conversion from Blender data to OpenSubdiv data, and
* time spent on topology orientation on OpenSubdiv C-API side. */
* time spent on topology orientation on OpenSubdiv C-API side.
*/
double topology_refiner_creation_time;
/* Total time spent in blender::bke::subdiv::subdiv_to_mesh(). */
/** Total time spent in #blender::bke::subdiv::subdiv_to_mesh(). */
double subdiv_to_mesh_time;
/* Geometry (mesh vertices) creation time during SUBDIV_TO_MESH. */
/** Geometry (mesh vertices) creation time during SUBDIV_TO_MESH. */
double subdiv_to_mesh_geometry_time;
/* Time spent on evaluator creation from topology refiner. */
/** Time spent on evaluator creation from topology refiner. */
double evaluator_creation_time;
/* Time spent on evaluator->refine(). */
/** Time spent on evaluator->refine(). */
double evaluator_refine_time;
/* Total time spent on whole CCG creation. */
/** Total time spent on whole CCG creation. */
double subdiv_to_ccg_time;
/* Time spent on CCG elements evaluation/initialization. */
/** Time spent on CCG elements evaluation/initialization. */
double subdiv_to_ccg_elements_time;
/* Time spent on CCG elements evaluation/initialization. */
/** Time spent on CCG elements evaluation/initialization. */
double topology_compare_time;
};
double values_[NUM_SUBDIV_STATS_VALUES];
};
/* Per-value timestamp on when corresponding stats_begin() was
* called. */
/**
* Per-value timestamp on when corresponding stats_begin() was
* called.
*/
double begin_timestamp_[NUM_SUBDIV_STATS_VALUES];
};
/* Functor which evaluates displacement at a given (u, v) of given ptex face. */
/** Functor which evaluates displacement at a given (u, v) of given ptex face. */
struct Displacement {
/* Initialize displacement evaluator.
/**
* Initialize displacement evaluator.
*
* Is called right before evaluation is actually needed. This allows to do
* some lazy initialization, like allocate evaluator from a main thread but
* then do actual evaluation from background job. */
* then do actual evaluation from background job.
*/
void (*initialize)(Displacement *displacement);
/* Return displacement which is to be added to the original coordinate.
/**
* Return displacement which is to be added to the original coordinate.
*
* NOTE: This function is supposed to return "continuous" displacement for
* \note This function is supposed to return "continuous" displacement for
* each pf PTex faces created for special (non-quad) face. This means,
* if displacement is stored on per-corner manner (like MDisps for multires)
* this is up the displacement implementation to average boundaries of the
* displacement grids if needed.
*
* Averaging of displacement for vertices created for over coarse vertices
* and edges is done by subdiv code. */
* and edges is done by subdiv code.
*/
void (*eval_displacement)(Displacement *displacement,
int ptex_face_index,
float u,
@@ -142,43 +158,49 @@ struct Displacement {
const float3 &dPdv,
float3 &r_D);
/* Free the data, not the evaluator itself. */
/** Free the data, not the evaluator itself. */
void (*free)(Displacement *displacement);
void *user_data;
};
/* This structure contains everything needed to construct subdivided surface.
/**
* This structure contains everything needed to construct subdivided surface.
* It does not specify storage, memory layout or anything else.
* It is possible to create different storage's (like, grid based CPU side
* buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
* Subdiv structure. */
* Subdiv structure.
*/
struct Subdiv {
/* Settings this subdivision surface is created for.
/**
* Settings this subdivision surface is created for.
*
* It is read-only after assignment in BKE_subdiv_new_from_FOO(). */
* It is read-only after assignment in `BKE_subdiv_new_from_FOO()`.
*/
Settings settings;
/* Topology refiner includes all the glue logic to feed Blender side
* topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
* drawer. */
/**
* Topology refiner includes all the glue logic to feed Blender side
* topology to OpenSubdiv. It can be shared by both evaluator and GL mesh drawer.
*/
blender::opensubdiv::TopologyRefinerImpl *topology_refiner;
/* CPU side evaluator. */
/** CPU side evaluator. */
OpenSubdiv_Evaluator *evaluator;
/* Optional displacement evaluator. */
/** Optional displacement evaluator. */
Displacement *displacement_evaluator;
/* Statistics for debugging. */
/** Statistics for debugging. */
SubdivStats stats;
/* Cached values, are not supposed to be accessed directly. */
/** Cached values, are not supposed to be accessed directly. */
struct {
/* Indexed by base face index, element indicates total number of ptex
/**
* Indexed by base face index, element indicates total number of ptex
* faces created for preceding base faces. This also stores the final
* ptex offset (the total number of PTex faces) at the end of the array
* so that algorithms can compute the number of ptex faces for a given
* face by computing the delta with the offset for the next face without
* using a separate data structure, e.g.:
*
* const int num_face_ptex_faces = face_ptex_offset[i + 1] - face_ptex_offset[i];
* `const int num_face_ptex_faces = face_ptex_offset[i + 1] - face_ptex_offset[i];`
*
* In total this array has a size of `num base faces + 1`.
*/
@@ -186,26 +208,32 @@ struct Subdiv {
} cache_;
};
/* --------------------------------------------------------------------
* Module.
*/
/* -------------------------------------------------------------------- */
/** \name Module
* \{ */
/* (De)initialize the entire subdivision surface module. */
void init();
void exit();
/* --------------------------------------------------------------------
* Conversion helpers.
*/
/** \} */
/* NOTE: uv_smooth is eSubsurfUVSmooth. */
/* -------------------------------------------------------------------- */
/** \name Conversion helpers.
* \{ */
/**
* \note uv_smooth is #eSubsurfUVSmooth.
*/
FVarLinearInterpolation fvar_interpolation_from_uv_smooth(int uv_smooth);
VtxBoundaryInterpolation vtx_boundary_interpolation_from_subsurf(int boundary_smooth);
/* --------------------------------------------------------------------
* Statistics.
*/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Statistics
* \{ */
void stats_init(SubdivStats *stats);
@@ -216,27 +244,34 @@ void stats_reset(SubdivStats *stats, StatsValue value);
void stats_print(const SubdivStats *stats);
/* --------------------------------------------------------------------
* Settings.
*/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Settings
* \{ */
bool settings_equal(const Settings *settings_a, const Settings *settings_b);
/* --------------------------------------------------------------------
* Construction.
*/
/** \} */
/* Construct new subdivision surface descriptor, from scratch, using given
* settings and topology. */
/* -------------------------------------------------------------------- */
/** \name Construction
* \{ */
/**
* Construct new subdivision surface descriptor, from scratch, using given
* settings and topology.
*/
Subdiv *new_from_converter(const Settings *settings, OpenSubdiv_Converter *converter);
Subdiv *new_from_mesh(const Settings *settings, const Mesh *mesh);
/* Similar to above, but will not re-create descriptor if it was created for the
/**
* Similar to above, but will not re-create descriptor if it was created for the
* same settings and topology.
* If settings or topology did change, the existing descriptor is freed and a
* new one is created from scratch.
*
* NOTE: It is allowed to pass NULL as an existing subdivision surface
* \note It is allowed to pass NULL as an existing subdivision surface
* descriptor. This will create a new descriptor without any extra checks.
*/
Subdiv *update_from_converter(Subdiv *subdiv,
@@ -246,9 +281,11 @@ Subdiv *update_from_mesh(Subdiv *subdiv, const Settings *settings, const Mesh *m
void free(Subdiv *subdiv);
/* --------------------------------------------------------------------
* Displacement API.
*/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Displacement API
* \{ */
void displacement_attach_from_multires(Subdiv *subdiv,
const Mesh *mesh,
@@ -256,57 +293,72 @@ void displacement_attach_from_multires(Subdiv *subdiv,
void displacement_detach(Subdiv *subdiv);
/* --------------------------------------------------------------------
* Topology helpers.
*/
/** \} */
/* For each element in the array, this stores the total number of ptex faces up to that element,
/* -------------------------------------------------------------------- */
/** \name Topology helpers
* \{ */
/**
* For each element in the array, this stores the total number of ptex faces up to that element,
* with the total number of ptex faces being the last element in the array. The array is of length
* `base face count + 1`. */
* `base face count + 1`.
*/
int *face_ptex_offset_get(Subdiv *subdiv);
/* --------------------------------------------------------------------
* PTex faces and grids.
*/
/** \} */
/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
* (grid_u, grid_v) within a grid. */
/* -------------------------------------------------------------------- */
/** \name PTex faces and grids
* \{ */
/**
* For a given (ptex_u, ptex_v) within a ptex face get corresponding
* (grid_u, grid_v) within a grid.
*/
BLI_INLINE void ptex_face_uv_to_grid_uv(float ptex_u,
float ptex_v,
float *r_grid_u,
float *r_grid_v);
BLI_INLINE float2 ptex_face_uv_to_grid_uv(const float2 &ptex_uv);
/* Inverse of above. */
/** Inverse of above. */
BLI_INLINE void grid_uv_to_ptex_face_uv(float grid_u,
float grid_v,
float *r_ptex_u,
float *r_ptex_v);
/* For a given subdivision level (which is NOT refinement level) get size of
/**
* For a given subdivision level (which is NOT refinement level) get size of
* CCG grid (number of grid points on a side).
*/
BLI_INLINE int grid_size_from_level(int level);
/* Find per-corner coordinate with given per-face UV coord.
/**
* Find per-corner coordinate with given per-face UV coord.
* Only handles quad and works in normalized coordinates.
*
* NOTE: Output coordinates are in ptex coordinates. */
* \note Output coordinates are in ptex coordinates.
*/
BLI_INLINE int rotate_quad_to_corner(float quad_u,
float quad_v,
float *r_corner_u,
float *r_corner_v);
BLI_INLINE float2 rotate_quad_to_corner(int corner, const float2 &quad);
/* Converts (u, v) coordinate from within a grid to a quad coordinate in
* normalized ptex coordinates. */
/**
* Converts (u, v) coordinate from within a grid to a quad coordinate in
* normalized ptex coordinates.
*/
BLI_INLINE void rotate_grid_to_quad(
int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v);
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
/** Convert Blender edge crease value to OpenSubdiv sharpness. */
BLI_INLINE float crease_to_sharpness(float crease);
BLI_INLINE float sharpness_to_crease(float sharpness);
/** \} */
} // namespace blender::bke::subdiv
#include "intern/subdiv_inline.hh" // IWYU pragma: export

View File

@@ -26,51 +26,57 @@ namespace blender::bke::subdiv {
struct Subdiv;
}
/* --------------------------------------------------------------------
* Masks.
*/
/* -------------------------------------------------------------------- */
/** \name Masks
* \{ */
/* Functor which evaluates mask value at a given (u, v) of given ptex face. */
/** Functor which evaluates mask value at a given (u, v) of given ptex face. */
struct SubdivCCGMaskEvaluator {
float (*eval_mask)(SubdivCCGMaskEvaluator *mask_evaluator,
int ptex_face_index,
float u,
float v);
/* Free the data, not the evaluator itself. */
/** Free the data, not the evaluator itself. */
void (*free)(SubdivCCGMaskEvaluator *mask_evaluator);
void *user_data;
};
/* Return true if mesh has mask and evaluator can be used. */
/** Return true if mesh has mask and evaluator can be used. */
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh);
/* --------------------------------------------------------------------
* SubdivCCG.
*/
/** \} */
/* -------------------------------------------------------------------- */
/** \name SubdivCCG.
* \{ */
struct SubdivToCCGSettings {
/* Resolution at which regular ptex (created for quad face) are being
/**
* Resolution at which regular ptex (created for quad face) are being
* evaluated. This defines how many vertices final mesh will have: every
* regular ptex has resolution^2 vertices. Special (irregular, or ptex
* created for a corner of non-quad face) will have resolution of
* `resolution - 1`. */
* `resolution - 1`.
*/
int resolution;
/* Denotes which extra layers to be added to CCG elements. */
/** Denotes which extra layers to be added to CCG elements. */
bool need_normal;
bool need_mask;
};
struct SubdivCCGCoord {
/* Index of the grid within SubdivCCG::grids array. */
/** Index of the grid within SubdivCCG::grids array. */
int grid_index;
/* Coordinate within the grid. */
/** Coordinate within the grid. */
short x, y;
/* Returns the coordinate for the index in an array sized to contain all grid vertices (including
* duplicates). */
/**
* Returns the coordinate for the index in an array sized to contain all grid vertices
* (including duplicates).
*/
static SubdivCCGCoord from_index(const CCGKey &key, int index)
{
const int grid_index = index / key.grid_area;
@@ -84,8 +90,10 @@ struct SubdivCCGCoord {
return coord;
}
/* Returns the index for the coordinate in an array sized to contain all grid vertices (including
* duplicates). */
/**
* Returns the index for the coordinate in an array sized to contain all grid vertices
* (including duplicates).
*/
int to_index(const CCGKey &key) const
{
return key.grid_area * this->grid_index +
@@ -93,31 +101,39 @@ struct SubdivCCGCoord {
}
};
/* Definition of an edge which is adjacent to at least one of the faces. */
/** Definition of an edge which is adjacent to at least one of the faces. */
struct SubdivCCGAdjacentEdge {
/* Indexed by adjacent face index, then by point index on the edge.
* points to a coordinate into the grids. */
/**
* Indexed by adjacent face index, then by point index on the edge.
* points to a coordinate into the grids.
*/
blender::Vector<blender::Array<SubdivCCGCoord>> boundary_coords;
};
/* Definition of a vertex which is adjacent to at least one of the faces. */
/** Definition of a vertex which is adjacent to at least one of the faces. */
struct SubdivCCGAdjacentVertex {
/* Indexed by adjacent face index, points to a coordinate in the grids. */
/** Indexed by adjacent face index, points to a coordinate in the grids. */
blender::Vector<SubdivCCGCoord> corner_coords;
};
/* Representation of subdivision surface which uses CCG grids. */
/** Representation of subdivision surface which uses CCG grids. */
struct SubdivCCG : blender::NonCopyable {
/* This is a subdivision surface this CCG was created for.
/**
* This is a subdivision surface this CCG was created for.
*
* TODO(sergey): Make sure the whole descriptor is valid, including all the
* displacement attached to the surface. */
* displacement attached to the surface.
*/
blender::bke::subdiv::Subdiv *subdiv = nullptr;
/* A level at which geometry was subdivided. This is what defines grid
* resolution. It is NOT the topology refinement level. */
/**
* A level at which geometry was subdivided. This is what defines grid
* resolution. It is NOT the topology refinement level.
*/
int level = -1;
/* Resolution of grid. All grids have matching resolution, and resolution
* is same as ptex created for non-quad faces. */
/**
* Resolution of grid. All grids have matching resolution, and resolution
* is same as ptex created for non-quad faces.
*/
int grid_size = -1;
/** The number of vertices in each grid (grid_size ^2). */
int grid_area = -1;
@@ -133,26 +149,30 @@ struct SubdivCCG : blender::NonCopyable {
/** Optional mask values with the same indexing as #positions. */
blender::Array<float> masks;
/* Faces from which grids are emitted. Owned by base mesh. */
/** Faces from which grids are emitted. Owned by base mesh. */
blender::OffsetIndices<int> faces;
/* The face in #faces for each grid. Owned by base mesh (See #Mesh::corner_to_face_map()). */
/** The face in #faces for each grid. Owned by base mesh (See #Mesh::corner_to_face_map()). */
blender::Span<int> grid_to_face_map;
/* Edges which are adjacent to faces.
/**
* Edges which are adjacent to faces.
*
* Maps from coarse edge to a directional `grid_size` * 2 map of indices to `SubdivCCGCoord`,
* indexed by OpenSubdiv base mesh edge.
*
* Used for faster grid stitching, at the cost of extra memory.
*/
*/
blender::Array<SubdivCCGAdjacentEdge> adjacent_edges;
/* Vertices which are adjacent to faces.
/**
* Vertices which are adjacent to faces.
*
* Maps from coarse vertex to `SubdivCCGCoord`, indexed by OpenSubdiv base mesh vertex.
*
* Used for faster grid stitching, at the cost of extra memory.
*/
*/
blender::Array<SubdivCCGAdjacentVertex> adjacent_verts;
/** Store the visibility of the items in each grid. If empty, everything is visible. */
@@ -170,56 +190,59 @@ struct SubdivCCG : blender::NonCopyable {
/* TODO(sergey): Is this really best way to go? Kind of annoying to have
* such use-related flags in a more or less generic structure. */
struct {
/* Corresponds to MULTIRES_COORDS_MODIFIED. */
/** Corresponds to MULTIRES_COORDS_MODIFIED. */
bool coords = false;
/* Corresponds to MULTIRES_HIDDEN_MODIFIED. */
/** Corresponds to MULTIRES_HIDDEN_MODIFIED. */
bool hidden = false;
} dirty;
~SubdivCCG();
};
/* Create CCG representation of subdivision surface.
/**
* Create CCG representation of subdivision surface.
*
* NOTE: CCG stores dense vertices in a grid-like storage. There is no edges or
* \note CCG stores dense vertices in a grid-like storage. There is no edges or
* faces information's for the high-poly surface.
*
* NOTE: Subdiv is expected to be refined and ready for evaluation.
* NOTE: CCG becomes an owner of subdiv.
* \note Subdiv is expected to be refined and ready for evaluation.
* \note CCG becomes an owner of subdiv.
*
* TODO(sergey): Allow some user-counter or more explicit control over who owns
* the Subdiv. The goal should be to allow viewport GL Mesh and CCG to share
* same Subsurf without conflicts. */
* same Subsurf without conflicts.
*/
std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(blender::bke::subdiv::Subdiv &subdiv,
const SubdivToCCGSettings &settings,
const Mesh &coarse_mesh,
SubdivCCGMaskEvaluator *mask_evaluator = nullptr);
/* Helper function, creates Mesh structure which is properly setup to use
/**
* Helper function, creates Mesh structure which is properly setup to use
* grids.
*/
Mesh *BKE_subdiv_to_ccg_mesh(blender::bke::subdiv::Subdiv &subdiv,
const SubdivToCCGSettings &settings,
const Mesh &coarse_mesh);
/* Create a key for accessing grid elements at a given level. */
/** Create a key for accessing grid elements at a given level. */
CCGKey BKE_subdiv_ccg_key(const SubdivCCG &subdiv_ccg, int level);
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg);
/* Recalculate all normals based on grid element coordinates. */
/** Recalculate all normals based on grid element coordinates. */
void BKE_subdiv_ccg_recalc_normals(SubdivCCG &subdiv_ccg);
/* Update normals of affected faces. */
/** Update normals of affected faces. */
void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const blender::IndexMask &face_mask);
/* Average grid coordinates and normals along the grid boundaries. */
/** Average grid coordinates and normals along the grid boundaries. */
void BKE_subdiv_ccg_average_grids(SubdivCCG &subdiv_ccg);
/* Similar to above, but only updates given faces. */
/** Similar to above, but only updates given faces. */
void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg,
const blender::IndexMask &face_mask);
/* Get geometry counters at the current subdivision level. */
/** Get geometry counters at the current subdivision level. */
void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg,
int &r_num_vertices,
int &r_num_edges,
@@ -258,10 +281,12 @@ bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG &subdiv_ccg, const SubdivC
* - For the boundary element two neighbor elements on the boundary (from same grid) and one
* element inside of every neighboring grid. */
/* Get actual neighbors of the given coordinate.
/**
* Get actual neighbors of the given coordinate.
*
* If include_duplicates is true, vertices in other grids that match
* the current vertex are added at the end of the coords array. */
* the current vertex are added at the end of the coords array.
*/
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord,
bool include_duplicates,
@@ -283,9 +308,11 @@ enum class SubdivCCGAdjacencyType : int8_t {
Edge,
};
/* Returns if a grid coordinates is adjacent to a coarse mesh edge, vertex or nothing. If it is
/**
* Returns if a grid coordinates is adjacent to a coarse mesh edge, vertex or nothing. If it is
* adjacent to an edge, r_v1 and r_v2 will be set to the two vertices of that edge. If it is
* adjacent to a vertex, r_v1 and r_v2 will be the index of that vertex. */
* adjacent to a vertex, r_v1 and r_v2 will be the index of that vertex.
*/
SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord,
@@ -294,7 +321,7 @@ SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
int &r_v1,
int &r_v2);
/* Determines if a given grid coordinate is on a coarse mesh boundary. */
/** Determines if a given grid coordinate is on a coarse mesh boundary. */
bool BKE_subdiv_ccg_coord_is_mesh_boundary(blender::OffsetIndices<int> faces,
blender::Span<int> corner_verts,
blender::BitSpan boundary_verts,
@@ -350,3 +377,5 @@ inline int grid_xy_to_vert(const CCGKey &key, const int grid, const int x, const
}
} // namespace blender::bke::ccg
/** \} */

View File

@@ -17,13 +17,15 @@ namespace blender::bke::subdiv {
struct Subdiv;
/* Special version of subdivision surface which calculates final positions for coarse vertices.
/**
* Special version of subdivision surface which calculates final positions for coarse vertices.
* Effectively is pushing the coarse positions to the limit surface.
*
* One of the usage examples is calculation of crazy space of subdivision modifier, allowing to
* paint on a deformed mesh with sub-surf on it.
*
* vertex_cos are supposed to hold coordinates of the coarse mesh. */
* vertex_cos are supposed to hold coordinates of the coarse mesh.
*/
void deform_coarse_vertices(Subdiv *subdiv,
const Mesh *coarse_mesh,
MutableSpan<float3> vert_positions);

View File

@@ -24,7 +24,7 @@ enum eSubdivEvaluatorType {
SUBDIV_EVALUATOR_TYPE_GPU,
};
/* Returns true if evaluator is ready for use. */
/** Returns true if evaluator is ready for use. */
bool eval_begin(Subdiv *subdiv,
eSubdivEvaluatorType evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache,
@@ -40,10 +40,12 @@ bool eval_begin_from_mesh(Subdiv *subdiv,
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.
/**
* Makes sure displacement evaluator is initialized.
*
* NOTE: This function must be called once before evaluating displacement or
* final surface position. */
* \note This function must be called once before evaluating displacement or
* final surface position.
*/
void eval_init_displacement(Subdiv *subdiv);
/* Single point queries. */
@@ -61,11 +63,11 @@ void eval_limit_point_and_derivatives(Subdiv *subdiv,
void eval_limit_point_and_normal(
Subdiv *subdiv, int ptex_face_index, float u, float v, float3 &r_P, float3 &r_N);
/* Evaluate smoothly interpolated vertex data (such as ORCO). */
/** Evaluate smoothly interpolated vertex data (such as ORCO). */
void eval_vertex_data(
Subdiv *subdiv, int ptex_face_index, float u, float v, float r_vertex_data[]);
/* Evaluate face-varying layer (such as UV). */
/** Evaluate face-varying layer (such as UV). */
void eval_face_varying(Subdiv *subdiv,
int face_varying_channel,
int ptex_face_index,
@@ -73,12 +75,14 @@ void eval_face_varying(Subdiv *subdiv,
float v,
float2 &r_face_varying);
/* NOTE: Expects derivatives to be correct.
/**
* \note Expects derivatives to be correct.
*
* TODO(sergey): This is currently used together with
* eval_final_point() which can easily evaluate derivatives.
* Would be nice to have displacement evaluation function which does not require
* knowing derivatives ahead of a time. */
* knowing derivatives ahead of a time.
*/
void eval_displacement(Subdiv *subdiv,
int ptex_face_index,
float u,
@@ -87,7 +91,7 @@ void eval_displacement(Subdiv *subdiv,
const float3 &dPdv,
float3 &r_D);
/* Evaluate point on a limit surface with displacement applied to it. */
/** Evaluate point on a limit surface with displacement applied to it. */
float3 eval_final_point(Subdiv *subdiv, int ptex_face_index, float u, float v);
} // namespace blender::bke::subdiv

View File

@@ -93,56 +93,63 @@ using ForeachVertexOfLooseEdgeCb = void (*)(const ForeachContext *context,
int subdiv_vertex_index);
struct ForeachContext {
/* Is called when topology information becomes available.
/**
* Is called when topology information becomes available.
* Is only called once.
*
* NOTE: If this callback returns false, the foreach loop is aborted.
* \note If this callback returns false, the foreach loop is aborted.
*/
ForeachTopologyInformationCb topology_info = nullptr;
/* These callbacks are called from every ptex which shares "emitting"
/**
* These callbacks are called from every ptex which shares "emitting"
* vertex or edge.
*/
ForeachVertexFromCornerCb vertex_every_corner = nullptr;
ForeachVertexFromEdgeCb vertex_every_edge = nullptr;
/* Those callbacks are run once per subdivision vertex, ptex is undefined
/**
* 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.
* the multi-threaded environment and which shares "emitting" vertex or edge.
*/
ForeachVertexFromCornerCb vertex_corner = nullptr;
ForeachVertexFromEdgeCb vertex_edge = nullptr;
/* Called exactly once, always corresponds to a single ptex face. */
/** Called exactly once, always corresponds to a single ptex face. */
ForeachVertexInnerCb vertex_inner = nullptr;
/* Called once for each loose vertex. One loose coarse vertex corresponds
/**
* Called once for each loose vertex. One loose coarse vertex corresponds
* to a single subdivision vertex.
*/
ForeachLooseCb vertex_loose = nullptr;
/* Called once per vertex created for loose edge. */
/** Called once per vertex created for loose edge. */
ForeachVertexOfLooseEdgeCb vertex_of_loose_edge = nullptr;
/* NOTE: If subdivided edge does not come from coarse edge, ORIGINDEX_NONE
/**
* \note If subdivided edge does not come from coarse edge, ORIGINDEX_NONE
* will be passed as coarse_edge_index.
*/
ForeachEdgeCb edge = nullptr;
/* NOTE: If subdivided loop does not come from coarse loop, ORIGINDEX_NONE
/**
* \note If subdivided loop does not come from coarse loop, ORIGINDEX_NONE
* will be passed as coarse_loop_index.
*/
ForeachLoopCb loop = nullptr;
ForeachPolygonCb poly = nullptr;
/* User-defined pointer, to allow callbacks know something about context the
/**
* User-defined pointer, to allow callbacks know something about context the
* traversal is happening for.
*/
void *user_data = nullptr;
/* Initial value of TLS data. */
/** Initial value of TLS data. */
void *user_data_tls = nullptr;
/* Size of TLS data. */
/** Size of TLS data. */
size_t user_data_tls_size = 0;
/* Function to free TLS storage. */
/** Function to free TLS storage. */
void (*user_data_tls_free)(void *tls) = nullptr;
};
/* Invokes callbacks in the order and with values which corresponds to creation
/**
* Invokes callbacks in the order and with values which corresponds to creation
* of final subdivided mesh.
*
* Main goal is to abstract all the traversal routines to give geometry element
@@ -154,6 +161,7 @@ struct ForeachContext {
* TODO(sergey): Need to either get rid of subdiv or of coarse_mesh.
* The main point here is to be able to get base level topology, which can be
* done with either of those. Having both of them is kind of redundant.
*/
bool foreach_subdiv_geometry(Subdiv *subdiv,
const ForeachContext *context,

View File

@@ -13,8 +13,10 @@
#include "DNA_mesh_types.h"
/* Hardcoded for until GPU shaders are automatically generated, then we will have a more
* programmatic way of detecting this. */
/**
* Hard-coded for until GPU shaders are automatically generated,
* then we will have a more programmatic way of detecting this.
*/
#define MAX_GPU_SUBDIV_SSBOS 12
struct Mesh;
@@ -27,27 +29,29 @@ struct Subdiv;
struct Settings;
} // namespace blender::bke::subdiv
/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
/** Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
struct SubsurfRuntimeData {
/* Subdivision settings, exists before descriptor or mesh wrapper is created. */
/** Subdivision settings, exists before descriptor or mesh wrapper is created. */
blender::bke::subdiv::Settings settings;
/* Cached subdivision surface descriptor, with topology and settings. */
/** Cached subdivision surface descriptor, with topology and settings. */
blender::bke::subdiv::Subdiv *subdiv_cpu;
blender::bke::subdiv::Subdiv *subdiv_gpu;
/* Recent usage markers for UI diagnostics. To avoid UI flicker due to races
/**
* Recent usage markers for UI diagnostics. To avoid UI flicker due to races
* between evaluation and UI redraw, they are set to 2 when an evaluator is used,
* and count down every frame. */
* and count down every frame.
*/
char used_cpu, used_gpu;
/* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
/** Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
bool has_gpu_subdiv;
int resolution;
bool use_optimal_display;
bool use_loop_normals;
/* Cached from the draw code for stats display. */
/** Cached from the draw code for stats display. */
int stats_totvert;
int stats_totedge;
int stats_faces_num;