Subdiv: CCG, initial grids stitching implementation

Currently is only working on an "inner" grid boundaries.
Need to implement averaging across face edges.
This commit is contained in:
Sergey Sharybin 2018-09-18 17:09:08 +02:00
parent 41c039d6e9
commit 9bf3e0299b
4 changed files with 149 additions and 21 deletions

View File

@ -55,6 +55,18 @@ typedef struct SubdivToCCGSettings {
bool need_mask;
} SubdivToCCGSettings;
/* This is actually a coarse face, which consists of multiple CCG grids. */
typedef struct SubdivCCGFace {
/* Total number of grids in this face.
*
* This 1:1 corresponds to a number of corners (or loops) from a coarse
* face.
*/
int num_grids;
/* Index of first grid from this face in SubdivCCG->grids array. */
int start_grid_index;
} SubdivCCGFace;
/* Representation of subdivision surface which uses CCG grids. */
typedef struct SubdivCCG {
/* This is a subdivision surface this CCG was created for.
@ -104,6 +116,12 @@ typedef struct SubdivCCG {
int normal_offset;
int mask_offset;
/* Faces from which grids are emitted. */
int num_faces;
SubdivCCGFace *faces;
/* Indexed by grid index, points to corresponding face from `faces`. */
SubdivCCGFace **grid_faces;
struct DMFlagMat *grid_flag_mats;
BLI_bitmap **grid_hidden;
@ -161,4 +179,7 @@ void BKE_subdiv_ccg_key_top_level(
/* Recalculate all normals based on grid element coordinates. */
void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg);
/* Average grid coordinates and normals along the grid boundatries. */
void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg);
#endif /* __BKE_SUBDIV_CCG_H__ */

View File

@ -1338,20 +1338,29 @@ void multires_modifier_update_hidden(DerivedMesh *dm)
void multires_stitch_grids(Object *ob)
{
/* utility for smooth brush */
if (ob && ob->derivedFinal) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)ob->derivedFinal;
CCGFace **faces;
int totface;
if (ccgdm->pbvh) {
BKE_pbvh_get_grid_updates(ccgdm->pbvh, false, (void ***)&faces, &totface);
if (totface) {
ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
MEM_freeN(faces);
}
}
if (ob == NULL) {
return;
}
SculptSession *sculpt_session = ob->sculpt;
if (sculpt_session == NULL) {
return;
}
PBVH *pbvh = sculpt_session->pbvh;
SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg;
if (pbvh == NULL || subdiv_ccg == NULL) {
return;
}
BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS);
/* NOTE: Currently CCG does not keep track of faces, making it impossible
* to use BKE_pbvh_get_grid_updates().
*/
CCGFace **faces;
int num_faces;
BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
if (num_faces) {
/* TODO(sergey): Only aveerage actually affected faces. */
BKE_subdiv_ccg_average_grids(subdiv_ccg);
MEM_freeN(faces);
}
}

View File

@ -1197,7 +1197,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
pbvh,
subdiv_ccg->grids, subdiv_ccg->num_grids,
&key,
NULL,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden);
pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);

View File

@ -44,6 +44,8 @@
#include "BKE_subdiv.h"
#include "BKE_subdiv_eval.h"
#include "opensubdiv_topology_refiner_capi.h"
/* =============================================================================
* Generally useful internal helpers.
*/
@ -122,6 +124,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg,
{
const int element_size = element_size_bytes_get(subdiv_ccg);
/* Allocate memory for surface grids. */
const int num_faces = coarse_mesh->totpoly;
const int num_grids = coarse_mesh->totloop;
const int grid_size = grid_size_for_level_get(
subdiv_ccg, subdiv_ccg->level);
@ -149,6 +152,14 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg,
BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
}
/* TOOD(sergey): Allocate memory for loose elements. */
/* Allocate memory for faces. */
subdiv_ccg->num_faces = num_faces;
if (num_faces) {
subdiv_ccg->faces = MEM_calloc_arrayN(
num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces");
subdiv_ccg->grid_faces = MEM_calloc_arrayN(
num_grids, sizeof(SubdivCCGFace*), "Subdiv CCG grid faces");
}
}
/* =============================================================================
@ -219,9 +230,11 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
const int grid_size = subdiv_ccg->grid_size;
const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
const int element_size = element_size_bytes_get(subdiv_ccg);
SubdivCCGFace *faces = subdiv_ccg->faces;
SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[
coarse_poly->loopstart + corner];
const int grid_index = coarse_poly->loopstart + corner;
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
for (int y = 0; y < grid_size; y++) {
const float grid_v = (float)y * grid_size_1_inv;
for (int x = 0; x < grid_size; x++) {
@ -237,6 +250,8 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
&grid[grid_element_offset]);
}
}
/* Assign grid's face. */
grid_faces[grid_index] = &faces[coarse_poly_index];
}
}
@ -248,9 +263,11 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
const int grid_size = subdiv_ccg->grid_size;
const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
const int element_size = element_size_bytes_get(subdiv_ccg);
SubdivCCGFace *faces = subdiv_ccg->faces;
SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[
coarse_poly->loopstart + corner];
const int grid_index = coarse_poly->loopstart + corner;
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
for (int y = 0; y < grid_size; y++) {
const float u = 1.0f - ((float)y * grid_size_1_inv);
for (int x = 0; x < grid_size; x++) {
@ -266,6 +283,8 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
&grid[grid_element_offset]);
}
}
/* Assign grid's face. */
grid_faces[grid_index] = &faces[coarse_poly_index];
}
}
@ -275,6 +294,7 @@ static void subdiv_ccg_eval_grids_task(
const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGEvalGridsData *data = userdata_v;
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
const Mesh *coarse_mesh = data->coarse_mesh;
const MPoly *coarse_mpoly = coarse_mesh->mpoly;
const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
@ -284,6 +304,10 @@ static void subdiv_ccg_eval_grids_task(
else {
subdiv_ccg_eval_special_grid(data, coarse_poly);
}
/* Assign information in the faces. */
subdiv_ccg->faces[coarse_poly_index].num_grids = coarse_poly->totloop;
subdiv_ccg->faces[coarse_poly_index].start_grid_index =
coarse_poly->loopstart;
}
static bool subdiv_ccg_evaluate_grids(
@ -330,6 +354,7 @@ SubdivCCG *BKE_subdiv_to_ccg(
{
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
subdiv_ccg->subdiv = subdiv;
subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
subdiv_ccg->grid_size =
grid_size_for_level_get(subdiv_ccg, subdiv_ccg->level);
@ -341,7 +366,6 @@ SubdivCCG *BKE_subdiv_to_ccg(
return NULL;
}
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
subdiv_ccg->subdiv = subdiv;
return subdiv_ccg;
}
@ -378,6 +402,7 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
if (subdiv_ccg->subdiv != NULL) {
BKE_subdiv_free(subdiv_ccg->subdiv);
}
MEM_SAFE_FREE(subdiv_ccg->faces);
MEM_freeN(subdiv_ccg);
}
@ -528,7 +553,8 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
RecalcInnerNormalsData data = {
.subdiv_ccg = subdiv_ccg,
.key = &key};
.key = &key
};
RecalcInnerNormalsTLSData tls_data = {NULL};
ParallelRangeSettings parallel_range_settings;
BLI_parallel_range_settings_defaults(&parallel_range_settings);
@ -549,4 +575,76 @@ void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg)
return;
}
subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg);
BKE_subdiv_ccg_average_grids(subdiv_ccg);
}
/* =============================================================================
* Boundary averaging/stitching.
*/
typedef struct AverageInnerGridsData {
SubdivCCG *subdiv_ccg;
CCGKey *key;
} AverageInnerGridsData;
static void average_grid_element_value_v3(float a[3], float b[3])
{
add_v3_v3(a, b);
mul_v3_fl(a, 0.5f);
copy_v3_v3(b, a);
}
static void average_grid_element(SubdivCCG *subdiv_ccg,
CCGKey *key,
CCGElem *grid_element_a,
CCGElem *grid_element_b)
{
average_grid_element_value_v3(CCG_elem_co(key, grid_element_a),
CCG_elem_co(key, grid_element_b));
if (subdiv_ccg->has_normal) {
average_grid_element_value_v3(CCG_elem_no(key, grid_element_a),
CCG_elem_no(key, grid_element_b));
}
}
static void subdiv_ccg_average_inner_grids_task(
void *__restrict userdata_v,
const int face_index,
const ParallelRangeTLS *__restrict UNUSED(tls_v))
{
AverageInnerGridsData *data = userdata_v;
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
CCGKey *key = data->key;
CCGElem **grids = subdiv_ccg->grids;
SubdivCCGFace *faces = subdiv_ccg->faces;
SubdivCCGFace *face = &faces[face_index];
const int num_face_grids = face->num_grids;
const int grid_size = subdiv_ccg->grid_size;
CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1];
for (int corner = 0; corner < num_face_grids; corner++) {
CCGElem *grid = grids[face->start_grid_index + corner];
for (int i = 0; i < grid_size; i++) {
CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0);
CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i);
average_grid_element(
subdiv_ccg, key, prev_grid_element, grid_element);
}
prev_grid = grid;
}
}
void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg)
{
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
AverageInnerGridsData data = {
.subdiv_ccg = subdiv_ccg,
.key = &key,
};
ParallelRangeSettings parallel_range_settings;
BLI_parallel_range_settings_defaults(&parallel_range_settings);
BLI_task_parallel_range(0, subdiv_ccg->num_faces,
&data,
subdiv_ccg_average_inner_grids_task,
&parallel_range_settings);
}