diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-09-06 18:06:17 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-09-11 17:37:02 +0300 |
commit | 3fbdcefa174dd85972b7b63c0955e3a8d42f6943 (patch) | |
tree | 6b1d4b1538f18e847f2e12204a79d89b937edc28 /source/blender | |
parent | 998a80435819387ce88d922d7fd7049e8e27b7bf (diff) |
Subdiv: Initial implementation of CCG
Attempts to substitude CCGDM with an OpenSubdiv based structure
which has less abstraction levels. The missing part in this
substitude is a face pointers which old CCGDM/multires code was
using to stitch faces (averaging boundaries).
Another curial bit missing: "reshaping" of multires CD_MDISPS
to the state of new PBVH grids.
The new code is only available when OpenSubdiv modifier is
enabled (WITH_OPENSUBDIV_MODIFIER=ON) and with debug value of
128. This is so this WIP code is not interfering with current
production machines in the studio.
Reviewers: brecht
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D3685
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_paint.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_subdiv.h | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_subdiv_ccg.h | 19 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_runtime.c | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/paint.c | 39 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_ccg.c | 314 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_stats.c | 8 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_hide.c | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_types.h | 3 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_multires.c | 84 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_subsurf.c | 64 |
11 files changed, 492 insertions, 56 deletions
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index c440a634c9f..ade23a2a9ca 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -261,7 +261,7 @@ int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene); -struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Object *ob, struct Mesh *me_eval_deform); +struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob); enum { SCULPT_MASK_LAYER_CALC_VERT = (1 << 0), diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index 4ebb5d1ac66..09fcce369d4 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -66,6 +66,8 @@ typedef enum eSubdivStatsValue { SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY, SUBDIV_STATS_EVALUATOR_CREATE, SUBDIV_STATS_EVALUATOR_REFINE, + SUBDIV_STATS_SUBDIV_TO_CCG, + SUBDIV_STATS_SUBDIV_TO_CCG_ELEMENTS, NUM_SUBDIV_STATS_VALUES, } eSubdivStatsValue; @@ -86,6 +88,10 @@ typedef struct SubdivStats { double evaluator_creation_time; /* Time spent on evaluator->refine(). */ double evaluator_refine_time; + /* Total time spent on whole CCG creation. */ + double subdiv_to_ccg_time; + /* Time spent on CCG elements evaluation/initialization. */ + double subdiv_to_ccg_elements_time; }; double values_[NUM_SUBDIV_STATS_VALUES]; }; diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index b1acf43ad25..8f8a605d309 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -33,10 +33,12 @@ #define __BKE_SUBDIV_CCG_H__ #include "BKE_customdata.h" +#include "BLI_bitmap.h" #include "BLI_sys_types.h" struct CCGElem; struct CCGKey; +struct DMFlagMat; struct Mesh; struct Subdiv; @@ -67,7 +69,12 @@ typedef struct SubdivCCG { * corresponding to face-corners of coarse mesh, each grid has * grid_size^2 elements. */ + /* Indexed by a grid index, points to a grid data which is stored in + * grids_storage. + */ struct CCGElem **grids; + /* Flat array of all grids' data. */ + unsigned char *grids_storage; int num_grids; /* Loose edges, each array element contains grid_size elements * corresponding to vertices created by subdividing coarse edges. @@ -91,6 +98,9 @@ typedef struct SubdivCCG { int normal_offset; int mask_offset; + struct DMFlagMat *grid_flag_mats; + BLI_bitmap **grid_hidden; + /* TODO(sergey): Consider adding some accessors to a "decoded" geometry, * to make integration with draw manager and such easy. */ @@ -106,9 +116,18 @@ struct SubdivCCG *BKE_subdiv_to_ccg( const SubdivToCCGSettings *settings, const struct Mesh *coarse_mesh); + /* Destroy CCG representation of subdivision surface. */ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg); +/* Helper function, creates Mesh structure which is properly setup to use + * grids. + */ +struct Mesh *BKE_subdiv_to_ccg_mesh( + struct Subdiv *subdiv, + const SubdivToCCGSettings *settings, + const struct Mesh *coarse_mesh); + /* Create a key for accessing grid elements at a given level. */ void BKE_subdiv_ccg_key( struct CCGKey *key, const SubdivCCG *subdiv_ccg, int level); diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index 60699589a77..51dd9a9ea3a 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -43,6 +43,7 @@ #include "BKE_bvhutils.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" +#include "BKE_subdiv_ccg.h" /* -------------------------------------------------------------------- */ /** \name Mesh Runtime Struct Utils @@ -196,6 +197,11 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) { bvhcache_free(&mesh->runtime.bvh_cache); MEM_SAFE_FREE(mesh->runtime.looptris.array); + /* TODO(sergey): Does this really belong here? */ + if (mesh->runtime.subsurf_ccg != NULL) { + BKE_subdiv_ccg_destroy(mesh->runtime.subsurf_ccg); + mesh->runtime.subsurf_ccg = NULL; + } } /** \} */ diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 12cdb4586c1..edea8784715 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -55,6 +55,7 @@ #include "BKE_animsys.h" #include "BKE_brush.h" +#include "BKE_ccg.h" #include "BKE_colortools.h" #include "BKE_deform.h" #include "BKE_main.h" @@ -72,6 +73,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" #include "DEG_depsgraph.h" @@ -910,7 +912,6 @@ void BKE_sculpt_update_mesh_elements( ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH); - Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH); /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ if (mmd && ob->mode & OB_MODE_SCULPT) { @@ -931,7 +932,7 @@ void BKE_sculpt_update_mesh_elements( ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); } - PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform); + PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); BLI_assert(pbvh == ss->pbvh); UNUSED_VARS_NDEBUG(pbvh); MEM_SAFE_FREE(ss->pmap); @@ -1139,7 +1140,7 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob) return pbvh; } -static PBVH *build_regular_mesh_pbvh(Object *ob, Mesh *me_eval_deform) +static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) { Mesh *me = BKE_object_get_original_mesh(ob); const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); @@ -1174,7 +1175,24 @@ static PBVH *build_regular_mesh_pbvh(Object *ob, Mesh *me_eval_deform) return pbvh; } -PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform) +static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + PBVH *pbvh = BKE_pbvh_new(); + BKE_pbvh_build_grids( + pbvh, + subdiv_ccg->grids, subdiv_ccg->num_grids, + &key, + NULL, + subdiv_ccg->grid_flag_mats, + subdiv_ccg->grid_hidden); + pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); + return pbvh; +} + +PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) { if (ob == NULL || ob->sculpt == NULL) { return NULL; @@ -1189,8 +1207,17 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform) /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */ pbvh = build_pbvh_for_dynamic_topology(ob); } - else if (ob->type == OB_MESH) { - pbvh = build_regular_mesh_pbvh(ob, me_eval_deform); + else { + Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); + Mesh *mesh_eval = object_eval->data; + if (mesh_eval->runtime.subsurf_ccg != NULL) { + pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subsurf_ccg); + } + else if (ob->type == OB_MESH) { + Mesh *me_eval_deform = mesh_get_eval_deform( + depsgraph, DEG_get_evaluated_scene(depsgraph), ob, CD_MASK_BAREMESH); + pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform); + } } ob->sculpt->pbvh = pbvh; diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index d1769c5324d..33785c09936 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -34,15 +34,74 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_bits.h" +#include "BLI_task.h" + +#include "BKE_DerivedMesh.h" #include "BKE_ccg.h" +#include "BKE_mesh.h" #include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" + +/* ============================================================================= + * Generally useful internal helpers. + */ + +/* For a given subdivision level (NOT the refinement level) get resolution + * of grid. + */ +static int grid_size_for_level_get(const SubdivCCG *subdiv_ccg, int level) +{ + BLI_assert(level >= 1); + BLI_assert(level <= subdiv_ccg->level); + UNUSED_VARS_NDEBUG(subdiv_ccg); + return (1 << (level - 1)) + 1; +} + +/* Number of floats in per-vertex elements. */ +static int num_element_float_get(const SubdivCCG *subdiv_ccg) +{ + /* We always have 3 floats for coordinate. */ + int num_floats = 3; + if (subdiv_ccg->has_normal) { + num_floats += 3; + } + if (subdiv_ccg->has_mask) { + num_floats += 1; + } + return num_floats; +} + +/* Per-vertex element size in bytes. */ +static int element_size_bytes_get(const SubdivCCG *subdiv_ccg) +{ + return sizeof(float) * num_element_float_get(subdiv_ccg); +} + +/* ============================================================================= + * Internal helpers for CCG creation. + */ static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, const SubdivToCCGSettings *settings) { /* CCG always contains coordinates. Rest of layers are coming after them. */ int layer_offset = sizeof(float) * 3; - /* Normals. */ + /* Mask. */ + if (settings->need_mask) { + subdiv_ccg->has_mask = true; + subdiv_ccg->mask_offset = layer_offset; + layer_offset += sizeof(float); + } + else { + subdiv_ccg->has_mask = false; + subdiv_ccg->mask_offset = -1; + } + /* Normals. + * + * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter + * here, but some other area might in theory depend memory layout. + */ if (settings->need_normal) { subdiv_ccg->has_normal = true; subdiv_ccg->normal_offset = layer_offset; @@ -52,65 +111,264 @@ static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, subdiv_ccg->has_normal = false; subdiv_ccg->normal_offset = -1; } - /* Mask. */ - if (settings->need_mask) { - subdiv_ccg->has_mask = true; - subdiv_ccg->mask_offset = layer_offset; - layer_offset += sizeof(float); +} + +/* NOTE: Grid size and layer flags are to be filled in before calling this + * function. + */ +static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, + const Mesh *coarse_mesh) +{ + const int element_size = element_size_bytes_get(subdiv_ccg); + /* Allocate memory for surface grids. */ + const int num_grids = coarse_mesh->totloop; + const int grid_size = grid_size_for_level_get( + subdiv_ccg, subdiv_ccg->level); + const int grid_area = grid_size * grid_size; + subdiv_ccg->num_grids = num_grids; + subdiv_ccg->grids = + MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids"); + subdiv_ccg->grids_storage = MEM_calloc_arrayN( + num_grids, ((size_t)grid_area) * element_size, + "subdiv ccg grids storage"); + const size_t grid_size_in_bytes = (size_t)grid_area * element_size; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + const size_t grid_offset = grid_size_in_bytes * grid_index; + subdiv_ccg->grids[grid_index] = + (CCGElem *)&subdiv_ccg->grids_storage[grid_offset]; + } + /* Grid material flags. */ + subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN( + num_grids, sizeof(DMFlagMat), "ccg grid material flags"); + /* Grid hidden flags. */ + subdiv_ccg->grid_hidden = MEM_calloc_arrayN( + num_grids, sizeof(BLI_bitmap *), "ccg grid material flags"); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + subdiv_ccg->grid_hidden[grid_index] = + BLI_BITMAP_NEW(grid_area, "ccg grid hidden"); + } + /* TOOD(sergey): Allocate memory for loose elements. */ +} + +/* ============================================================================= + * Grids evaluation. + */ + +typedef struct CCGEvalGridsData { + SubdivCCG *subdiv_ccg; + Subdiv *subdiv; + const Mesh *coarse_mesh; + int *face_petx_offset; +} CCGEvalGridsData; + +static void subdiv_ccg_eval_grid_element( + CCGEvalGridsData *data, + const int ptex_face_index, + const float u, const float v, + unsigned char *element) +{ + /* TODO(sergey): Support displacement. */ + if (data->subdiv_ccg->has_normal) { + BKE_subdiv_eval_limit_point_and_normal( + data->subdiv, ptex_face_index, u, v, + (float *)element, + (float *)(element + data->subdiv_ccg->normal_offset)); } else { - subdiv_ccg->has_mask = false; - subdiv_ccg->mask_offset = -1; + BKE_subdiv_eval_limit_point( + data->subdiv, ptex_face_index, u, v, (float *)element); } } -static int grid_size_for_level_get(const SubdivCCG *subdiv_ccg, int level) +BLI_INLINE void rotate_corner_to_quad(const int corner, + const float u, const float v, + float *r_u, float *r_v) { - BLI_assert(level >= 1); - BLI_assert(level <= subdiv_ccg->level); - UNUSED_VARS_NDEBUG(subdiv_ccg); - return (1 << (level - 1)) + 1; + if (corner == 0) { + *r_u = 0.5f - v * 0.5f; + *r_v = 0.5f - u * 0.5f; + } + else if (corner == 1) { + *r_u = 0.5f + u * 0.5f; + *r_v = 0.5f - v * 0.5f; + } + else if (corner == 2) { + *r_u = 0.5f + v * 0.5f; + *r_v = 0.5f + u * 0.5f; + } + else if (corner == 3) { + *r_u = 0.5f - u * 0.5f; + *r_v = 0.5f + v * 0.5f; + } + else { + BLI_assert(!"Unexpected corner configuration"); + } } -/* Per-vertex element size in bytes. */ -static int element_size_get(const SubdivCCG *subdiv_ccg) +static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, + const MPoly *coarse_poly) { - /* We always have 3 floats for coordinate. */ - int num_floats = 3; - if (subdiv_ccg->has_normal) { - num_floats += 3; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + const int coarse_poly_index = coarse_poly - data->coarse_mesh->mpoly; + const int ptex_face_index = data->face_petx_offset[coarse_poly_index]; + 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); + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + unsigned char *grid = (unsigned char *)subdiv_ccg->grids[ + coarse_poly->loopstart + corner]; + 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++) { + const float grid_u = (float)x * grid_size_1_inv; + float u, v; + rotate_corner_to_quad(corner, grid_u, grid_v, &u, &v); + const size_t grid_element_index = (size_t)y * grid_size + x; + const size_t grid_element_offset = + grid_element_index * element_size; + subdiv_ccg_eval_grid_element( + data, + ptex_face_index, u, v, + &grid[grid_element_offset]); + } + } } - if (subdiv_ccg->has_mask) { - num_floats += 1; +} + +static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, + const MPoly *coarse_poly) +{ + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + const int coarse_poly_index = coarse_poly - data->coarse_mesh->mpoly; + 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); + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + unsigned char *grid = (unsigned char *)subdiv_ccg->grids[ + coarse_poly->loopstart + corner]; + 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++) { + const float v = 1.0f - ((float)x * grid_size_1_inv); + const int ptex_face_index = + data->face_petx_offset[coarse_poly_index] + corner; + const size_t grid_element_index = (size_t)y * grid_size + x; + const size_t grid_element_offset = + grid_element_index * element_size; + subdiv_ccg_eval_grid_element( + data, + ptex_face_index, u, v, + &grid[grid_element_offset]); + } + } + } +} + +static void subdiv_ccg_eval_grids_task( + void *__restrict userdata_v, + const int coarse_poly_index, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + CCGEvalGridsData *data = userdata_v; + const Mesh *coarse_mesh = data->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + if (coarse_poly->totloop == 4) { + subdiv_ccg_eval_regular_grid(data, coarse_poly); + } + else { + subdiv_ccg_eval_special_grid(data, coarse_poly); + } +} + +static bool subdiv_ccg_evaluate_grids(SubdivCCG *subdiv_ccg, + Subdiv *subdiv, + const Mesh *coarse_mesh) +{ + /* Make sure evaluator is ready. */ + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) { + if (coarse_mesh->totpoly) { + return false; + } } - return sizeof(float) * num_floats; + /* Initialize data passed to all the tasks. */ + CCGEvalGridsData data; + data.subdiv_ccg = subdiv_ccg; + data.subdiv = subdiv; + data.coarse_mesh = coarse_mesh; + data.face_petx_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + /* Threaded grids evaluation/ */ + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + BLI_task_parallel_range(0, coarse_mesh->totpoly, + &data, + subdiv_ccg_eval_grids_task, + ¶llel_range_settings); + return true; } +/* ============================================================================= + * Public API. + */ + SubdivCCG *BKE_subdiv_to_ccg( - Subdiv *UNUSED(subdiv), + Subdiv *subdiv, const SubdivToCCGSettings *settings, - const Mesh *UNUSED(coarse_mesh)) + const Mesh *coarse_mesh) { - SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG *), "subdiv ccg"); - subdiv_ccg->level = settings->resolution >> 1; + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg"); + subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1); subdiv_ccg->grid_size = grid_size_for_level_get(subdiv_ccg, subdiv_ccg->level); subdiv_ccg_init_layers(subdiv_ccg, settings); - return NULL; + subdiv_ccg_alloc_elements(subdiv_ccg, coarse_mesh); + if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, coarse_mesh)) { + BKE_subdiv_ccg_destroy(subdiv_ccg); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + return NULL; + } + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + return subdiv_ccg; +} + +Mesh *BKE_subdiv_to_ccg_mesh( + Subdiv *subdiv, + const SubdivToCCGSettings *settings, + const Mesh *coarse_mesh) +{ + SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg( + subdiv, settings, coarse_mesh); + if (subdiv_ccg == NULL) { + return NULL; + } + Mesh *result = BKE_mesh_new_nomain_from_template( + coarse_mesh, 0, 0, 0, 0, 0); + result->runtime.subsurf_ccg = subdiv_ccg; + return result; } void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg) { + const int num_grids = subdiv_ccg->num_grids; MEM_SAFE_FREE(subdiv_ccg->grids); + MEM_SAFE_FREE(subdiv_ccg->grids_storage); MEM_SAFE_FREE(subdiv_ccg->edges); MEM_SAFE_FREE(subdiv_ccg->vertices); + MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats); + if (subdiv_ccg->grid_hidden != NULL) { + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + MEM_freeN(subdiv_ccg->grid_hidden[grid_index]); + } + MEM_freeN(subdiv_ccg->grid_hidden); + } MEM_freeN(subdiv_ccg); } void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level) { key->level = level; - key->elem_size = element_size_get(subdiv_ccg); + key->elem_size = element_size_bytes_get(subdiv_ccg); key->grid_size = grid_size_for_level_get(subdiv_ccg, level); key->grid_area = key->grid_size * key->grid_size; key->grid_bytes = key->elem_size * key->grid_area; diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c index f2219961ab7..a0cd1d909b7 100644 --- a/source/blender/blenkernel/intern/subdiv_stats.c +++ b/source/blender/blenkernel/intern/subdiv_stats.c @@ -40,6 +40,8 @@ void BKE_subdiv_stats_init(SubdivStats *stats) stats->subdiv_to_mesh_geometry_time = 0.0; stats->evaluator_creation_time = 0.0; stats->evaluator_refine_time = 0.0; + stats->subdiv_to_ccg_time = 0.0; + stats->subdiv_to_ccg_elements_time = 0.0; } void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value) @@ -79,6 +81,12 @@ void BKE_subdiv_stats_print(const SubdivStats *stats) STATS_PRINT_TIME(stats, evaluator_refine_time, "Evaluator refine time"); + STATS_PRINT_TIME(stats, + subdiv_to_ccg_time, + "Subdivision to CCG time"); + STATS_PRINT_TIME(stats, + subdiv_to_ccg_elements_time, + " Elements time"); #undef STATS_PRINT_TIME } diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index a0589623f92..0336928a7c9 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -391,8 +391,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) clip_planes_from_rect(C, clip_planes, &rect); - Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, CTX_data_scene(C), ob, CD_MASK_BAREMESH); - pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform); + pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); BLI_assert(ob->sculpt->pbvh == pbvh); get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area); diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index a91f2f05c1a..be190d656b4 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -53,6 +53,7 @@ struct MVert; struct Material; struct Mesh; struct Multires; +struct SubdivCCG; # # @@ -83,6 +84,8 @@ struct MLoopTri_Store { typedef struct Mesh_Runtime { struct EditMeshData *edit_data; void *batch_cache; + struct SubdivCCG *subsurf_ccg; + void *pad1; int64_t cd_dirty_vert; int64_t cd_dirty_edge; diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 870d91282b6..847b34b7aa6 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -42,10 +42,12 @@ #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" +#include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_modifier.h" #include "BKE_subdiv.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subdiv_mesh.h" #include "BKE_subsurf.h" @@ -143,25 +145,74 @@ static DerivedMesh *applyModifier( } #ifdef WITH_OPENSUBDIV_MODIFIER -static Mesh *applyModifier_subdiv(ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh) + +/* Subdivide into fully qualified mesh. */ + +static Mesh *multires_as_mesh(MultiresModifierData *mmd, + const ModifierEvalContext *ctx, + Mesh *mesh, + Subdiv *subdiv) +{ + Mesh *result = mesh; + const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); + const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY); + const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + Object *object = ctx->object; + SubdivToMeshSettings mesh_settings; + BKE_multires_subdiv_mesh_settings_init( + &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify); + if (mesh_settings.resolution < 3) { + return result; + } + BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); + result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); + return result; +} + +/* Subdivide into CCG. */ + +static void multires_ccg_settings_init(SubdivToCCGSettings *settings, + const MultiresModifierData *mmd, + const ModifierEvalContext *ctx, + Mesh *mesh) { + const bool has_mask = + CustomData_has_layer(&mesh->ldata, CD_GRID_PAINT_MASK); const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY); const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); Object *object = ctx->object; + const int level = multires_get_level( + scene, object, mmd, use_render_params, ignore_simplify); + settings->resolution = (1 << level) + 1; + settings->need_normal = true; + settings->need_mask = has_mask; +} + +static Mesh *multires_as_ccg(MultiresModifierData *mmd, + const ModifierEvalContext *ctx, + Mesh *mesh, + Subdiv *subdiv) +{ + Mesh *result = mesh; + SubdivToCCGSettings ccg_settings; + multires_ccg_settings_init(&ccg_settings, mmd, ctx, mesh); + if (ccg_settings.resolution < 3) { + return result; + } + result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh); + return result; +} + +static Mesh *applyModifier_subdiv(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *mesh) +{ Mesh *result = mesh; MultiresModifierData *mmd = (MultiresModifierData *)md; SubdivSettings subdiv_settings; BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); - SubdivToMeshSettings mesh_settings; - BKE_multires_subdiv_mesh_settings_init( - &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify); - if (subdiv_settings.level == 0 || mesh_settings.resolution < 3) { - /* NOTE: Shouldn't really happen, is supposed to be catched by - * isDisabled() callback. - */ + if (subdiv_settings.level == 0) { return result; } /* TODO(sergey): Try to re-use subdiv when possible. */ @@ -170,8 +221,17 @@ static Mesh *applyModifier_subdiv(ModifierData *md, /* Happens on bad topology, ut also on empty input mesh. */ return result; } - BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); - result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); + /* TODO(sergey): Some of production machines are using OpenSubdiv already. + * so better not enable semi-finished multires sculpting for now. Will give + * a wrong impression that things do work, eben though crucial areas are + * styill missing in implementation. + */ + if ((ctx->object->mode & OB_MODE_SCULPT) && G.debug_value == 128) { + result = multires_as_ccg(mmd, ctx, mesh, subdiv); + } + else { + result = multires_as_mesh(mmd, ctx, mesh, subdiv); + } /* TODO(sergey): Cache subdiv somehow. */ // BKE_subdiv_stats_print(&subdiv->stats); BKE_subdiv_free(subdiv); diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index ae9ffd076f7..deccec05190 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -44,6 +44,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_scene.h" #include "BKE_subdiv.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subdiv_mesh.h" #include "BKE_subsurf.h" @@ -170,6 +171,8 @@ static void subdiv_settings_init(SubdivSettings *settings, BKE_subdiv_fvar_interpolation_from_uv_smooth(smd->uv_smooth); } +/* Subdivide into fully qualified mesh. */ + static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings, const SubsurfModifierData *smd, const ModifierEvalContext *ctx) @@ -178,6 +181,50 @@ static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings, settings->resolution = (1 << level) + 1; } +static Mesh *subdiv_as_mesh(SubsurfModifierData *smd, + const ModifierEvalContext *ctx, + Mesh *mesh, + Subdiv *subdiv) +{ + Mesh *result = mesh; + SubdivToMeshSettings mesh_settings; + subdiv_mesh_settings_init(&mesh_settings, smd, ctx); + if (mesh_settings.resolution < 3) { + return result; + } + result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); + return result; +} + +/* Subdivide into CCG. */ + +static void subdiv_ccg_settings_init(SubdivToCCGSettings *settings, + const SubsurfModifierData *smd, + const ModifierEvalContext *ctx) +{ + const int level = subdiv_levels_for_modifier_get(smd, ctx); + settings->resolution = (1 << level) + 1; + settings->need_normal = true; + settings->need_mask = false; +} + +static Mesh *subdiv_as_ccg(SubsurfModifierData *smd, + const ModifierEvalContext *ctx, + Mesh *mesh, + Subdiv *subdiv) +{ + Mesh *result = mesh; + SubdivToCCGSettings ccg_settings; + subdiv_ccg_settings_init(&ccg_settings, smd, ctx); + if (ccg_settings.resolution < 3) { + return result; + } + result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh); + return result; +} + +/* Modifier itself. */ + static Mesh *applyModifier_subdiv(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) @@ -186,12 +233,7 @@ static Mesh *applyModifier_subdiv(ModifierData *md, SubsurfModifierData *smd = (SubsurfModifierData *) md; SubdivSettings subdiv_settings; subdiv_settings_init(&subdiv_settings, smd); - SubdivToMeshSettings mesh_settings; - subdiv_mesh_settings_init(&mesh_settings, smd, ctx); - if (subdiv_settings.level == 0 || mesh_settings.resolution < 3) { - /* NOTE: Shouldn't really happen, is supposed to be catched by - * isDisabled() callback. - */ + if (subdiv_settings.level == 0) { return result; } /* TODO(sergey): Try to re-use subdiv when possible. */ @@ -200,7 +242,15 @@ static Mesh *applyModifier_subdiv(ModifierData *md, /* Happens on bad topology, ut also on empty input mesh. */ return result; } - result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh); + /* TODO(sergey): Decide whether we ever want to use CCG for subsurf, + * maybe when it is a last modifier in the stack? + */ + if (true) { + result = subdiv_as_mesh(smd, ctx, mesh, subdiv); + } + else { + result = subdiv_as_ccg(smd, ctx, mesh, subdiv); + } /* TODO(sergey): Cache subdiv somehow. */ // BKE_subdiv_stats_print(&subdiv->stats); BKE_subdiv_free(subdiv); |