Cleanup: use doxygen comments for BKE_subdiv*
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user