Fix T60124: Multires modifier not reading data from external files

This commit is contained in:
Sergey Sharybin
2019-01-04 15:57:44 +01:00
parent bfac8a429c
commit b69cbe7d87
4 changed files with 60 additions and 29 deletions

View File

@@ -88,8 +88,7 @@ typedef struct SubdivStats {
struct { struct {
/* Time spend on creating topology refiner, which includes time /* Time spend on creating topology refiner, which includes time
* spend on conversion from Blender data to OpenSubdiv data, and * spend on conversion from Blender data to OpenSubdiv data, and
* time spend on topology orientation on OpenSubdiv C-API side. * time spend on topology orientation on OpenSubdiv C-API side. */
*/
double topology_refiner_creation_time; double topology_refiner_creation_time;
/* Total time spent in BKE_subdiv_to_mesh(). */ /* Total time spent in BKE_subdiv_to_mesh(). */
double subdiv_to_mesh_time; double subdiv_to_mesh_time;
@@ -108,13 +107,19 @@ typedef struct SubdivStats {
}; };
/* Per-value timestamp on when corresponding BKE_subdiv_stats_begin() was /* Per-value timestamp on when corresponding BKE_subdiv_stats_begin() was
* called. * called. */
*/
double begin_timestamp_[NUM_SUBDIV_STATS_VALUES]; double begin_timestamp_[NUM_SUBDIV_STATS_VALUES];
} SubdivStats; } SubdivStats;
/* Functor which evaluates dispalcement at a given (u, v) of given ptex face. */ /* Functor which evaluates dispalcement at a given (u, v) of given ptex face. */
typedef struct SubdivDisplacement { typedef struct SubdivDisplacement {
/* 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. */
void (*initialize)(struct SubdivDisplacement *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
@@ -124,8 +129,7 @@ typedef struct SubdivDisplacement {
* displacement grids if needed. * displacement grids if needed.
* *
* Averaging of displacement for vertices created for over coarse vertices * 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)(struct SubdivDisplacement *displacement, void (*eval_displacement)(struct SubdivDisplacement *displacement,
const int ptex_face_index, const int ptex_face_index,
const float u, const float v, const float u, const float v,
@@ -142,8 +146,7 @@ typedef struct SubdivDisplacement {
* It does not specify storage, memory layout or anything else. * It does not specify storage, memory layout or anything else.
* It is possible to create different storages (like, grid based CPU side * It is possible to create different storages (like, grid based CPU side
* buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same * buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
* Subdiv structure. * Subdiv structure. */
*/
typedef struct Subdiv { typedef struct Subdiv {
/* Settings this subdivision surface is created for. /* Settings this subdivision surface is created for.
* *
@@ -152,8 +155,7 @@ typedef struct Subdiv {
SubdivSettings settings; SubdivSettings settings;
/* Topology refiner includes all the glue logic to feed Blender side /* Topology refiner includes all the glue logic to feed Blender side
* topology to OpenSubdiv. It can be shared by both evaluator and GL mesh * topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
* drawer. * drawer. */
*/
struct OpenSubdiv_TopologyRefiner *topology_refiner; struct OpenSubdiv_TopologyRefiner *topology_refiner;
/* CPU side evaluator. */ /* CPU side evaluator. */
struct OpenSubdiv_Evaluator *evaluator; struct OpenSubdiv_Evaluator *evaluator;
@@ -200,7 +202,7 @@ void BKE_subdiv_free(Subdiv *subdiv);
void BKE_subdiv_displacement_attach_from_multires( void BKE_subdiv_displacement_attach_from_multires(
Subdiv *subdiv, Subdiv *subdiv,
const struct Mesh *mesh, struct Mesh *mesh,
const struct MultiresModifierData *mmd); const struct MultiresModifierData *mmd);
void BKE_subdiv_displacement_detach(Subdiv *subdiv); void BKE_subdiv_displacement_detach(Subdiv *subdiv);
@@ -212,8 +214,7 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
/* ============================= VARIOUS HELPERS ============================ */ /* ============================= VARIOUS HELPERS ============================ */
/* For a given (ptex_u, ptex_v) within a ptex face get corresponding /* For a given (ptex_u, ptex_v) within a ptex face get corresponding
* (grid_u, grid_v) within a grid. * (grid_u, grid_v) within a grid. */
*/
BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv( BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(
const float ptex_u, const float ptex_v, const float ptex_u, const float ptex_v,
float *r_grid_u, float *r_grid_v); float *r_grid_u, float *r_grid_v);
@@ -226,8 +227,7 @@ BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level);
/* Simplified version of mdisp_rot_face_to_crn, only handles quad and /* Simplified version of mdisp_rot_face_to_crn, only handles quad and
* works in normalized coordinates. * works in normalized coordinates.
* *
* NOTE: Output coordinates are in ptex coordinates. * NOTE: Output coordinates are in ptex coordinates. */
*/
BLI_INLINE int BKE_subdiv_rotate_quad_to_corner( BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(
const float u, const float v, const float u, const float v,
float *r_u, float *r_v); float *r_u, float *r_v);

View File

@@ -42,6 +42,12 @@ bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh); const struct Mesh *mesh);
/* Makes sure displacement evaluator is initialized.
*
* NOTE: This function must be called once before evaluating displacement or
* final surface position. */
void BKE_subdiv_eval_init_displacement(struct Subdiv *subdiv);
/* Single point queries. */ /* Single point queries. */
void BKE_subdiv_eval_limit_point( void BKE_subdiv_eval_limit_point(
@@ -77,8 +83,7 @@ void BKE_subdiv_eval_face_varying(
* TODO(sergey): This is currently used together with * TODO(sergey): This is currently used together with
* BKE_subdiv_eval_final_point() which cas easily evaluate derivatives. * BKE_subdiv_eval_final_point() which cas easily evaluate derivatives.
* Would be nice to have dispalcement evaluation function which does not require * Would be nice to have dispalcement evaluation function which does not require
* knowing derivatives ahead of a time. * knowing derivatives ahead of a time. */
*/
void BKE_subdiv_eval_displacement( void BKE_subdiv_eval_displacement(
struct Subdiv *subdiv, struct Subdiv *subdiv,
const int ptex_face_index, const int ptex_face_index,
@@ -96,8 +101,7 @@ void BKE_subdiv_eval_final_point(
* *
* Will evaluate patch at uniformly distributed (u, v) coordinates on a grid * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid
* of given resolution, producing resolution^2 evaluation points. The order * of given resolution, producing resolution^2 evaluation points. The order
* goes as u in rows, v in columns. * goes as u in rows, v in columns. */
*/
void BKE_subdiv_eval_limit_patch_resolution_point( void BKE_subdiv_eval_limit_patch_resolution_point(
struct Subdiv *subdiv, struct Subdiv *subdiv,

View File

@@ -49,20 +49,23 @@ typedef struct PolyCornerIndex {
typedef struct MultiresDisplacementData { typedef struct MultiresDisplacementData {
int grid_size; int grid_size;
/* Mesh is used to read external displacement. */
Mesh *mesh;
const MPoly *mpoly; const MPoly *mpoly;
const MDisps *mdisps; const MDisps *mdisps;
/* Indexed by ptex face index, contains polygon/corner which corresponds /* Indexed by ptex face index, contains polygon/corner which corresponds
* to it. * to it.
* *
* NOTE: For quad polygon this is an index of first corner only, since * NOTE: For quad polygon this is an index of first corner only, since
* there we only have one ptex. * there we only have one ptex. */
*/
PolyCornerIndex *ptex_poly_corner; PolyCornerIndex *ptex_poly_corner;
/* Sanity check, is used in debug builds.
* Controls that initialize() was called prior to eval_displacement(). */
bool is_initialized;
} MultiresDisplacementData; } MultiresDisplacementData;
/* Denotes which grid to use to average value of the displacement read from the /* Denotes which grid to use to average value of the displacement read from the
* grid which corresponds to the ptex face. * grid which corresponds to the ptex face. */
*/
typedef enum eAverageWith { typedef enum eAverageWith {
AVERAGE_WITH_NONE, AVERAGE_WITH_NONE,
AVERAGE_WITH_ALL, AVERAGE_WITH_ALL,
@@ -238,6 +241,16 @@ static void average_displacement(SubdivDisplacement *displacement,
} }
} }
static void initialize(SubdivDisplacement *displacement)
{
MultiresDisplacementData *data = displacement->user_data;
Mesh *mesh = data->mesh;
/* Make sure external displacement is read. */
CustomData_external_read(
&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
data->is_initialized = true;
}
static void eval_displacement(SubdivDisplacement *displacement, static void eval_displacement(SubdivDisplacement *displacement,
const int ptex_face_index, const int ptex_face_index,
const float u, const float v, const float u, const float v,
@@ -245,6 +258,7 @@ static void eval_displacement(SubdivDisplacement *displacement,
float r_D[3]) float r_D[3])
{ {
MultiresDisplacementData *data = displacement->user_data; MultiresDisplacementData *data = displacement->user_data;
BLI_assert(data->is_initialized);
const int grid_size = data->grid_size; const int grid_size = data->grid_size;
/* Get displacement in tangent space. */ /* Get displacement in tangent space. */
const MDisps *displacement_grid; const MDisps *displacement_grid;
@@ -254,8 +268,7 @@ static void eval_displacement(SubdivDisplacement *displacement,
&displacement_grid, &displacement_grid,
&grid_u, &grid_v); &grid_u, &grid_v);
/* Read displacement from the current displacement grid and see if any /* Read displacement from the current displacement grid and see if any
* averaging is needed. * averaging is needed. */
*/
float tangent_D[3]; float tangent_D[3];
eAverageWith average_with = eAverageWith average_with =
read_displacement_grid(displacement_grid, grid_size, read_displacement_grid(displacement_grid, grid_size,
@@ -279,8 +292,7 @@ static void free_displacement(SubdivDisplacement *displacement)
} }
/* TODO(sergey): This seems to be generally used information, which almost /* TODO(sergey): This seems to be generally used information, which almost
* worth adding to a subdiv itself, with possible cache of the value. * worth adding to a subdiv itself, with possible cache of the value. */
*/
static int count_num_ptex_faces(const Mesh *mesh) static int count_num_ptex_faces(const Mesh *mesh)
{ {
int num_ptex_faces = 0; int num_ptex_faces = 0;
@@ -323,25 +335,28 @@ static void displacement_data_init_mapping(SubdivDisplacement *displacement,
} }
static void displacement_init_data(SubdivDisplacement *displacement, static void displacement_init_data(SubdivDisplacement *displacement,
const Mesh *mesh, Mesh *mesh,
const MultiresModifierData *mmd) const MultiresModifierData *mmd)
{ {
MultiresDisplacementData *data = displacement->user_data; MultiresDisplacementData *data = displacement->user_data;
data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl); data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
data->mesh = mesh;
data->mpoly = mesh->mpoly; data->mpoly = mesh->mpoly;
data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
data->is_initialized = false;
displacement_data_init_mapping(displacement, mesh); displacement_data_init_mapping(displacement, mesh);
} }
static void displacement_init_functions(SubdivDisplacement *displacement) static void displacement_init_functions(SubdivDisplacement *displacement)
{ {
displacement->initialize = initialize;
displacement->eval_displacement = eval_displacement; displacement->eval_displacement = eval_displacement;
displacement->free = free_displacement; displacement->free = free_displacement;
} }
void BKE_subdiv_displacement_attach_from_multires( void BKE_subdiv_displacement_attach_from_multires(
Subdiv *subdiv, Subdiv *subdiv,
const Mesh *mesh, Mesh *mesh,
const MultiresModifierData *mmd) const MultiresModifierData *mmd)
{ {
/* Make sure we don't have previously assigned displacement. */ /* Make sure we don't have previously assigned displacement. */

View File

@@ -64,6 +64,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
else { else {
/* TODO(sergey): Check for topology change. */ /* TODO(sergey): Check for topology change. */
} }
BKE_subdiv_eval_init_displacement(subdiv);
return true; return true;
} }
@@ -159,6 +160,17 @@ bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
return true; return true;
} }
void BKE_subdiv_eval_init_displacement(Subdiv *subdiv)
{
if (subdiv->displacement_evaluator == NULL) {
return;
}
if (subdiv->displacement_evaluator->initialize == NULL) {
return;
}
subdiv->displacement_evaluator->initialize(subdiv->displacement_evaluator);
}
/* ========================== Single point queries ========================== */ /* ========================== Single point queries ========================== */
void BKE_subdiv_eval_limit_point( void BKE_subdiv_eval_limit_point(