Sculpt: Store multires grids data in separate arrays

For `SubdivCCG`, replace the dynamic array-of-struct data with separate
arrays for positions, normals, and masks. This decreases memory
bandwidth requirements for loops that only access one of these arrays.
It also significantly simplifies data access, making it more similar
to mesh data where it can just be accessed with indices.

In a simple test this change speeds up the multires sculpt brush
benchmark by 32%. It also slightly reduced BVH build time by about 12%.

In practice this means completely replacing usage of `CCGElem` for
`SubdivCCG`. The struct is still used in the older subsurf baking code
though. Removing that is a much trickier task that doesn't have short
term benefits.

Part of #118145.

Pull Request: https://projects.blender.org/blender/blender/pulls/127262
This commit is contained in:
Hans Goudey
2024-09-11 15:54:46 +02:00
committed by Hans Goudey
parent 4c2718e318
commit 1618448abd
32 changed files with 654 additions and 1055 deletions

View File

@@ -104,18 +104,3 @@ inline blender::float3 &CCG_elem_offset_co(const CCGKey &key, CCGElem *elem, int
{
return CCG_elem_co(key, CCG_elem_offset(key, elem, offset));
}
inline blender::float3 &CCG_elem_offset_no(const CCGKey &key, CCGElem *elem, int offset)
{
return CCG_elem_no(key, CCG_elem_offset(key, elem, offset));
}
inline float &CCG_elem_offset_mask(const CCGKey &key, CCGElem *elem, int offset)
{
return CCG_elem_mask(key, CCG_elem_offset(key, elem, offset));
}
inline CCGElem *CCG_elem_next(const CCGKey &key, CCGElem *elem)
{
return CCG_elem_offset(key, elem, 1);
}

View File

@@ -37,7 +37,6 @@
struct BMLog;
struct BMesh;
struct CCGElem;
struct CCGKey;
struct Depsgraph;
struct IsectRayPrecalc;
@@ -449,7 +448,7 @@ namespace blender::bke::pbvh {
*/
void update_bounds(const Depsgraph &depsgraph, const Object &object, Tree &pbvh);
void update_bounds_mesh(Span<float3> vert_positions, Tree &pbvh);
void update_bounds_grids(const CCGKey &key, Span<CCGElem *> elems, Tree &pbvh);
void update_bounds_grids(const CCGKey &key, Span<float3> positions, Tree &pbvh);
void update_bounds_bmesh(const BMesh &bm, Tree &pbvh);
/**
@@ -529,7 +528,7 @@ IndexMask node_draw_update_mask(const Tree &pbvh,
IndexMaskMemory &memory);
void node_update_mask_mesh(Span<float> mask, MeshNode &node);
void node_update_mask_grids(const CCGKey &key, Span<CCGElem *> grids, GridsNode &node);
void node_update_mask_grids(const CCGKey &key, Span<float> masks, GridsNode &node);
void node_update_mask_bmesh(int mask_offset, BMeshNode &node);
void node_update_visibility_mesh(Span<bool> hide_vert, MeshNode &node);
@@ -537,7 +536,7 @@ void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, GridsNode
void node_update_visibility_bmesh(BMeshNode &node);
void update_node_bounds_mesh(Span<float3> positions, MeshNode &node);
void update_node_bounds_grids(const CCGKey &key, Span<CCGElem *> grids, GridsNode &node);
void update_node_bounds_grids(const CCGKey &key, Span<float3> positions, GridsNode &node);
void update_node_bounds_bmesh(BMeshNode &node);
inline Span<int> MeshNode::faces() const

View File

@@ -122,37 +122,19 @@ struct SubdivCCG : blender::NonCopyable {
/* Resolution of grid. All grids have matching resolution, and resolution
* is same as ptex created for non-quad faces. */
int grid_size = -1;
/* Size of a single element of a grid (including coordinate and all the other layers).
* Measured in bytes. */
int grid_element_size = -1;
/* Grids represent limit surface, with displacement applied. Grids are
* corresponding to face-corners of coarse mesh, each grid has
* grid_size^2 elements.
/** The number of vertices in each grid (grid_size ^2). */
int grid_area = -1;
/** The number of grids (face corners) in the geometry (#faces.total_size()). */
int grids_num = -1;
/**
* Positions represent limit surface, with displacement applied. The vertices in each grid are
* stored in contiguous chunks of size #grid_area in the same order.
*/
/* Indexed by a grid index, points to a grid data which is stored in
* grids_storage. */
blender::Array<CCGElem *> grids;
/* Flat array of all grids' data. */
blender::Array<uchar> grids_storage;
/* Loose edges, each array element contains grid_size elements
* corresponding to vertices created by subdividing coarse edges. */
CCGElem **edges = nullptr;
int num_edges = -1;
/* Loose vertices. Every element corresponds to a loose vertex from a coarse
* mesh, every coarse loose vertex corresponds to a single subdivided
* element. */
CCGElem *vertices = nullptr;
int num_vertices = -1;
/* Denotes which layers present in the elements.
*
* Grids always has coordinates, followed by extra layers which are set to
* truth here.
*/
bool has_normal = false;
bool has_mask = false;
/* Offsets of corresponding data layers in the elements. */
int normal_offset = -1;
int mask_offset = -1;
blender::Array<blender::float3> positions;
/** Vertex normals with the same indexing as #positions. */
blender::Array<blender::float3> normals;
/** Optional mask values with the same indexing as #positions. */
blender::Array<float> masks;
/* Faces from which grids are emitted. Owned by base mesh. */
blender::OffsetIndices<int> faces;
@@ -350,3 +332,30 @@ inline void BKE_subdiv_ccg_foreach_visible_grid_vert(const CCGKey &key,
blender::bits::foreach_0_index(grid_hidden[grid], fn);
}
}
namespace blender::bke::ccg {
/** Find the range of vertices in the entire geometry that are part of a single grid. */
inline IndexRange grid_range(const int grid_area, const int grid)
{
return IndexRange(grid * grid_area, grid_area);
}
inline IndexRange grid_range(const CCGKey &key, const int grid)
{
return IndexRange(grid * key.grid_area, key.grid_area);
}
/** Find the range of vertices in the entire geometry that are part of a single face. */
inline IndexRange face_range(const OffsetIndices<int> faces, const CCGKey &key, const int face)
{
const IndexRange corners = faces[face];
return IndexRange(corners.start() * key.grid_area, corners.size() * key.grid_area);
}
/** Find the vertex index in the entire geometry at a specific coordinate in a specific grid. */
inline int grid_xy_to_vert(const CCGKey &key, const int grid, const int x, const int y)
{
return key.grid_area * grid + CCG_grid_xy_to_index(key.grid_size, x, y);
}
} // namespace blender::bke::ccg

View File

@@ -18,18 +18,22 @@
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
SubdivCCG *subdiv_ccg)
{
using namespace blender;
const CCGKey reshape_level_key = BKE_subdiv_ccg_key(*subdiv_ccg, reshape_context->reshape.level);
const int reshape_grid_size = reshape_context->reshape.grid_size;
const float reshape_grid_size_1_inv = 1.0f / (float(reshape_grid_size) - 1.0f);
int num_grids = subdiv_ccg->grids.size();
const Span<float3> positions = subdiv_ccg->positions;
const Span<float> masks = subdiv_ccg->masks;
int num_grids = subdiv_ccg->grids_num;
for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
CCGElem *ccg_grid = subdiv_ccg->grids[grid_index];
for (int y = 0; y < reshape_grid_size; ++y) {
const float v = float(y) * reshape_grid_size_1_inv;
for (int x = 0; x < reshape_grid_size; ++x) {
const float u = float(x) * reshape_grid_size_1_inv;
const int vert = bke::ccg::grid_xy_to_vert(reshape_level_key, grid_index, x, y);
GridCoord grid_coord;
grid_coord.grid_index = grid_index;
@@ -40,9 +44,7 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
reshape_context, &grid_coord);
BLI_assert(grid_element.displacement != nullptr);
memcpy(grid_element.displacement,
CCG_grid_elem_co(reshape_level_key, ccg_grid, x, y),
sizeof(float[3]));
memcpy(grid_element.displacement, positions[vert], sizeof(float[3]));
/* NOTE: The sculpt mode might have SubdivCCG's data out of sync from what is stored in
* the original object. This happens in the following scenario:
@@ -66,8 +68,8 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
/* NOTE: There is a known bug in Undo code that results in first Sculpt step
* after a Memfile one to never be undone (see #83806). This might be the root cause of
* this inconsistency. */
if (reshape_level_key.has_mask && grid_element.mask != nullptr) {
*grid_element.mask = CCG_grid_elem_mask(reshape_level_key, ccg_grid, x, y);
if (!subdiv_ccg->masks.is_empty() && grid_element.mask != nullptr) {
*grid_element.mask = masks[vert];
}
}
}

View File

@@ -1814,8 +1814,7 @@ blender::float3 SculptSession::active_vert_position(const Depsgraph &depsgraph,
if (std::holds_alternative<SubdivCCGCoord>(active_vert_)) {
const CCGKey key = BKE_subdiv_ccg_key_top_level(*this->subdiv_ccg);
const SubdivCCGCoord coord = std::get<SubdivCCGCoord>(active_vert_);
return CCG_grid_elem_co(key, this->subdiv_ccg->grids[coord.grid_index], coord.x, coord.y);
return this->subdiv_ccg->positions[coord.to_index(key)];
}
if (std::holds_alternative<BMVert *>(active_vert_)) {
BMVert *bm_vert = std::get<BMVert *>(active_vert_);
@@ -2519,7 +2518,7 @@ int BKE_sculptsession_vertex_count(const SculptSession *ss)
return ss->bm->totvert;
}
if (ss->subdiv_ccg) {
return ss->subdiv_ccg->grids.size() * BKE_subdiv_ccg_key_top_level(*ss->subdiv_ccg).grid_area;
return ss->subdiv_ccg->positions.size();
}
return ss->totvert;
}

View File

@@ -378,17 +378,14 @@ static int sum_group_sizes(const OffsetIndices<int> groups, const Span<int> indi
return count;
}
static Bounds<float3> calc_face_grid_bounds(const CCGKey &key,
const Span<CCGElem *> elems,
const IndexRange face)
static Bounds<float3> calc_face_grid_bounds(const OffsetIndices<int> faces,
const Span<float3> positions,
const CCGKey &key,
const int face)
{
Bounds<float3> bounds = negative_bounds();
for (const int grid : face) {
CCGElem *elem = elems[grid];
for (const int i : IndexRange(key.grid_area)) {
const float3 &position = CCG_elem_offset_co(key, elem, i);
math::min_max(position, bounds.min, bounds.max);
}
for (const float3 &position : positions.slice(ccg::face_range(faces, key, face))) {
math::min_max(position, bounds.min, bounds.max);
}
return bounds;
}
@@ -406,7 +403,10 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
}
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
if (positions.is_empty()) {
return pbvh;
}
const int leaf_limit = std::max(2500 / key.grid_area, 1);
@@ -418,7 +418,7 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
[&](const IndexRange range, const Bounds<float3> &init) {
Bounds<float3> current = init;
for (const int face : range) {
const Bounds<float3> bounds = calc_face_grid_bounds(key, elems, faces[face]);
const Bounds<float3> bounds = calc_face_grid_bounds(faces, positions, key, face);
face_centers[face] = bounds.center();
current = bounds::merge(current, bounds);
}
@@ -470,7 +470,7 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
}
});
update_bounds_grids(key, elems, *pbvh);
update_bounds_grids(key, positions, *pbvh);
store_bounds_orig(*pbvh);
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
@@ -1047,12 +1047,12 @@ void update_node_bounds_mesh(const Span<float3> positions, MeshNode &node)
node.bounds_ = bounds;
}
void update_node_bounds_grids(const CCGKey &key, const Span<CCGElem *> grids, GridsNode &node)
void update_node_bounds_grids(const CCGKey &key, const Span<float3> positions, GridsNode &node)
{
Bounds<float3> bounds = negative_bounds();
for (const int grid : node.grids()) {
for (const int i : IndexRange(key.grid_area)) {
math::min_max(CCG_elem_offset_co(key, grids[grid], i), bounds.min, bounds.max);
for (const float3 &position : positions.slice(bke::ccg::grid_range(key, grid))) {
math::min_max(position, bounds.min, bounds.max);
}
}
node.bounds_ = bounds;
@@ -1118,7 +1118,7 @@ void update_bounds_mesh(const Span<float3> vert_positions, Tree &pbvh)
}
}
void update_bounds_grids(const CCGKey &key, const Span<CCGElem *> elems, Tree &pbvh)
void update_bounds_grids(const CCGKey &key, const Span<float3> positions, Tree &pbvh)
{
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
@@ -1126,7 +1126,7 @@ void update_bounds_grids(const CCGKey &key, const Span<CCGElem *> elems, Tree &p
MutableSpan<GridsNode> nodes = pbvh.nodes<GridsNode>();
nodes_to_update.foreach_index(
GrainSize(1), [&](const int i) { update_node_bounds_grids(key, elems, nodes[i]); });
GrainSize(1), [&](const int i) { update_node_bounds_grids(key, positions, nodes[i]); });
if (!nodes.is_empty()) {
flush_bounds_to_parents(pbvh);
}
@@ -1158,8 +1158,7 @@ void update_bounds(const Depsgraph &depsgraph, const Object &object, Tree &pbvh)
const SculptSession &ss = *object.sculpt;
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
update_bounds_grids(key, elems, pbvh);
update_bounds_grids(key, subdiv_ccg.positions, pbvh);
break;
}
case Type::BMesh: {
@@ -1214,15 +1213,13 @@ static void update_mask_mesh(const Mesh &mesh,
[&](const int i) { node_update_mask_mesh(mask, nodes[i]); });
}
void node_update_mask_grids(const CCGKey &key, const Span<CCGElem *> grids, GridsNode &node)
void node_update_mask_grids(const CCGKey &key, const Span<float> masks, GridsNode &node)
{
BLI_assert(key.has_mask);
bool fully_masked = true;
bool fully_unmasked = true;
for (const int grid : node.grids()) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
const float mask = CCG_elem_offset_mask(key, elem, i);
for (const float mask : masks.slice(bke::ccg::grid_range(key, grid))) {
fully_masked &= mask == 1.0f;
fully_unmasked &= mask <= 0.0f;
}
@@ -1237,7 +1234,7 @@ static void update_mask_grids(const SubdivCCG &subdiv_ccg,
const IndexMask &nodes_to_update)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (!key.has_mask) {
if (subdiv_ccg.masks.is_empty()) {
nodes_to_update.foreach_index([&](const int i) {
nodes[i].flag_ &= ~PBVH_FullyMasked;
nodes[i].flag_ |= PBVH_FullyUnmasked;
@@ -1247,7 +1244,7 @@ static void update_mask_grids(const SubdivCCG &subdiv_ccg,
}
nodes_to_update.foreach_index(
GrainSize(1), [&](const int i) { node_update_mask_grids(key, subdiv_ccg.grids, nodes[i]); });
GrainSize(1), [&](const int i) { node_update_mask_grids(key, subdiv_ccg.masks, nodes[i]); });
}
void node_update_mask_bmesh(const int mask_offset, BMeshNode &node)
@@ -1510,7 +1507,7 @@ int BKE_pbvh_get_grid_num_verts(const Object &object)
const SculptSession &ss = *object.sculpt;
BLI_assert(blender::bke::object::pbvh_get(object)->type() == blender::bke::pbvh::Type::Grids);
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
return ss.subdiv_ccg->grids.size() * key.grid_area;
return ss.subdiv_ccg->grids_num * key.grid_area;
}
int BKE_pbvh_get_grid_num_faces(const Object &object)
@@ -1518,7 +1515,7 @@ int BKE_pbvh_get_grid_num_faces(const Object &object)
const SculptSession &ss = *object.sculpt;
BLI_assert(blender::bke::object::pbvh_get(object)->type() == blender::bke::pbvh::Type::Grids);
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
return ss.subdiv_ccg->grids.size() * square_i(key.grid_size - 1);
return ss.subdiv_ccg->grids_num * square_i(key.grid_size - 1);
}
/***************************** Node Access ***********************************/
@@ -2027,12 +2024,11 @@ static bool pbvh_grids_node_raycast(const SubdivCCG &subdiv_ccg,
const int grid_size = key.grid_size;
bool hit = false;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
if (node_positions.is_empty()) {
for (const int grid : grids) {
CCGElem *elem = elems[grid];
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
for (const short y : IndexRange(grid_size - 1)) {
for (const short x : IndexRange(grid_size - 1)) {
if (!grid_hidden.is_empty()) {
@@ -2040,10 +2036,11 @@ static bool pbvh_grids_node_raycast(const SubdivCCG &subdiv_ccg,
continue;
}
}
const std::array<const float *, 4> co{{CCG_grid_elem_co(key, elem, x, y + 1),
CCG_grid_elem_co(key, elem, x + 1, y + 1),
CCG_grid_elem_co(key, elem, x + 1, y),
CCG_grid_elem_co(key, elem, x, y)}};
const std::array<const float *, 4> co{
{grid_positions[CCG_grid_xy_to_index(grid_size, x, y + 1)],
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y + 1)],
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y)],
grid_positions[CCG_grid_xy_to_index(grid_size, x, y)]}};
if (ray_face_intersection_quad(
ray_start, isect_precalc, co[0], co[1], co[2], co[3], depth))
{
@@ -2362,12 +2359,12 @@ static bool pbvh_grids_node_nearest_to_ray(const SubdivCCG &subdiv_ccg,
const Span<int> grids = node.grids();
const int grid_size = key.grid_size;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
bool hit = false;
if (node_positions.is_empty()) {
for (const int grid : grids) {
CCGElem *elem = elems[grid];
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
for (const short y : IndexRange(grid_size - 1)) {
for (const short x : IndexRange(grid_size - 1)) {
if (!grid_hidden.is_empty()) {
@@ -2375,14 +2372,15 @@ static bool pbvh_grids_node_nearest_to_ray(const SubdivCCG &subdiv_ccg,
continue;
}
}
hit |= ray_face_nearest_quad(ray_start,
ray_normal,
CCG_grid_elem_co(key, elem, x, y),
CCG_grid_elem_co(key, elem, x + 1, y),
CCG_grid_elem_co(key, elem, x + 1, y + 1),
CCG_grid_elem_co(key, elem, x, y + 1),
depth,
dist_sq);
hit |= ray_face_nearest_quad(
ray_start,
ray_normal,
grid_positions[CCG_grid_xy_to_index(grid_size, x, y)],
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y)],
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y + 1)],
grid_positions[CCG_grid_xy_to_index(grid_size, x, y + 1)],
depth,
dist_sq);
}
}
}
@@ -2390,7 +2388,7 @@ static bool pbvh_grids_node_nearest_to_ray(const SubdivCCG &subdiv_ccg,
else {
for (const int i : grids.index_range()) {
const int grid = grids[i];
const Span<float3> grid_positions = node_positions.slice(key.grid_area * i, key.grid_area);
const Span<float3> grid_positions = node_positions.slice(bke::ccg::grid_range(key, i));
for (const short y : IndexRange(grid_size - 1)) {
for (const short x : IndexRange(grid_size - 1)) {
if (!grid_hidden.is_empty()) {

View File

@@ -38,6 +38,7 @@ using blender::Span;
using blender::Vector;
using blender::VectorSet;
using namespace blender::bke::subdiv;
using namespace blender::bke::ccg;
/* -------------------------------------------------------------------- */
/** \name Various forward declarations
@@ -55,65 +56,10 @@ void subdiv_ccg_average_faces_boundaries_and_corners(SubdivCCG &subdiv_ccg,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generally useful internal helpers
* \{ */
/* 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);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name 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]);
/* 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;
layer_offset += sizeof(float[3]);
}
else {
subdiv_ccg.has_normal = false;
subdiv_ccg.normal_offset = -1;
}
}
/* TODO(sergey): Make it more accessible function. */
static int topology_refiner_count_face_corners(const OpenSubdiv_TopologyRefiner *topology_refiner)
{
@@ -127,21 +73,21 @@ static int topology_refiner_count_face_corners(const OpenSubdiv_TopologyRefiner
/* NOTE: Grid size and layer flags are to be filled in before calling this
* function. */
static void subdiv_ccg_alloc_elements(SubdivCCG &subdiv_ccg, Subdiv &subdiv)
static void subdiv_ccg_alloc_elements(SubdivCCG &subdiv_ccg,
Subdiv &subdiv,
const SubdivToCCGSettings &settings)
{
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv.topology_refiner;
const int64_t element_size = element_size_bytes_get(subdiv_ccg);
/* Allocate memory for surface grids. */
const int64_t num_grids = topology_refiner_count_face_corners(topology_refiner);
const int64_t grid_size = grid_size_from_level(subdiv_ccg.level);
const int64_t grid_area = grid_size * grid_size;
subdiv_ccg.grid_element_size = element_size;
subdiv_ccg.grids.reinitialize(num_grids);
subdiv_ccg.grids_storage.reinitialize(num_grids * grid_area * element_size);
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];
subdiv_ccg.positions.reinitialize(num_grids * grid_area);
if (settings.need_normal) {
subdiv_ccg.normals.reinitialize(num_grids * grid_area);
}
if (settings.need_mask) {
subdiv_ccg.masks.reinitialize(num_grids * grid_area);
}
/* TODO(sergey): Allocate memory for loose elements. */
}
@@ -157,21 +103,21 @@ static void subdiv_ccg_eval_grid_element_limit(Subdiv &subdiv,
const int ptex_face_index,
const float u,
const float v,
uchar *element)
const int element)
{
if (subdiv.displacement_evaluator != nullptr) {
eval_final_point(&subdiv, ptex_face_index, u, v, (float *)element);
eval_final_point(&subdiv, ptex_face_index, u, v, subdiv_ccg.positions[element]);
}
else if (subdiv_ccg.has_normal) {
else if (!subdiv_ccg.normals.is_empty()) {
eval_limit_point_and_normal(&subdiv,
ptex_face_index,
u,
v,
(float *)element,
(float *)(element + subdiv_ccg.normal_offset));
subdiv_ccg.positions[element],
subdiv_ccg.normals[element]);
}
else {
eval_limit_point(&subdiv, ptex_face_index, u, v, (float *)element);
eval_limit_point(&subdiv, ptex_face_index, u, v, subdiv_ccg.positions[element]);
}
}
@@ -180,17 +126,16 @@ static void subdiv_ccg_eval_grid_element_mask(SubdivCCG &subdiv_ccg,
const int ptex_face_index,
const float u,
const float v,
uchar *element)
const int element)
{
if (!subdiv_ccg.has_mask) {
if (subdiv_ccg.masks.is_empty()) {
return;
}
float *mask_value_ptr = (float *)(element + subdiv_ccg.mask_offset);
if (mask_evaluator != nullptr) {
*mask_value_ptr = mask_evaluator->eval_mask(mask_evaluator, ptex_face_index, u, v);
subdiv_ccg.masks[element] = mask_evaluator->eval_mask(mask_evaluator, ptex_face_index, u, v);
}
else {
*mask_value_ptr = 0.0f;
subdiv_ccg.masks[element] = 0.0f;
}
}
@@ -200,7 +145,7 @@ static void subdiv_ccg_eval_grid_element(Subdiv &subdiv,
const int ptex_face_index,
const float u,
const float v,
uchar *element)
const int element)
{
subdiv_ccg_eval_grid_element_limit(subdiv, subdiv_ccg, ptex_face_index, u, v, element);
subdiv_ccg_eval_grid_element_mask(subdiv_ccg, mask_evaluator, ptex_face_index, u, v, element);
@@ -214,22 +159,21 @@ static void subdiv_ccg_eval_regular_grid(Subdiv &subdiv,
{
const int ptex_face_index = face_ptex_offset[face_index];
const int grid_size = subdiv_ccg.grid_size;
const int grid_area = subdiv_ccg.grid_area;
const float grid_size_1_inv = 1.0f / (grid_size - 1);
const int element_size = element_size_bytes_get(subdiv_ccg);
const IndexRange face = subdiv_ccg.faces[face_index];
for (int corner = 0; corner < face.size(); corner++) {
const int grid_index = face.start() + corner;
uchar *grid = (uchar *)subdiv_ccg.grids[grid_index];
const IndexRange range = grid_range(grid_area, grid_index);
for (int y = 0; y < grid_size; y++) {
const float grid_v = y * grid_size_1_inv;
for (int x = 0; x < grid_size; x++) {
const float grid_u = x * grid_size_1_inv;
float u, v;
rotate_grid_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;
const int element = range[CCG_grid_xy_to_index(grid_size, x, y)];
subdiv_ccg_eval_grid_element(
subdiv, subdiv_ccg, mask_evaluator, ptex_face_index, u, v, &grid[grid_element_offset]);
subdiv, subdiv_ccg, mask_evaluator, ptex_face_index, u, v, element);
}
}
}
@@ -242,21 +186,20 @@ static void subdiv_ccg_eval_special_grid(Subdiv &subdiv,
const int face_index)
{
const int grid_size = subdiv_ccg.grid_size;
const int grid_area = subdiv_ccg.grid_area;
const float grid_size_1_inv = 1.0f / (grid_size - 1);
const int element_size = element_size_bytes_get(subdiv_ccg);
const IndexRange face = subdiv_ccg.faces[face_index];
for (int corner = 0; corner < face.size(); corner++) {
const int grid_index = face.start() + corner;
const int ptex_face_index = face_ptex_offset[face_index] + corner;
uchar *grid = (uchar *)subdiv_ccg.grids[grid_index];
const IndexRange range = grid_range(grid_area, grid_index);
for (int y = 0; y < grid_size; y++) {
const float u = 1.0f - (y * grid_size_1_inv);
for (int x = 0; x < grid_size; x++) {
const float v = 1.0f - (x * grid_size_1_inv);
const size_t grid_element_index = size_t(y) * grid_size + x;
const size_t grid_element_offset = grid_element_index * element_size;
const int element = range[CCG_grid_xy_to_index(grid_size, x, y)];
subdiv_ccg_eval_grid_element(
subdiv, subdiv_ccg, mask_evaluator, ptex_face_index, u, v, &grid[grid_element_offset]);
subdiv, subdiv_ccg, mask_evaluator, ptex_face_index, u, v, element);
}
}
}
@@ -304,13 +247,6 @@ static SubdivCCGCoord subdiv_ccg_coord(int grid_index, int x, int y)
return coord;
}
static CCGElem *subdiv_ccg_coord_to_elem(const CCGKey &key,
const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord)
{
return CCG_grid_elem(key, subdiv_ccg.grids[coord.grid_index], coord.x, coord.y);
}
/* Returns storage where boundary elements are to be stored. */
static SubdivCCGCoord *subdiv_ccg_adjacent_edge_add_face(SubdivCCG &subdiv_ccg,
SubdivCCGAdjacentEdge &adjacent_edge)
@@ -469,10 +405,11 @@ std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
subdiv_ccg->subdiv = &subdiv;
subdiv_ccg->level = bitscan_forward_i(settings.resolution - 1);
subdiv_ccg->grid_size = grid_size_from_level(subdiv_ccg->level);
subdiv_ccg_init_layers(*subdiv_ccg, settings);
subdiv_ccg->grid_area = subdiv_ccg->grid_size * subdiv_ccg->grid_size;
subdiv_ccg->faces = coarse_mesh.faces();
subdiv_ccg->grids_num = subdiv_ccg->faces.total_size();
subdiv_ccg->grid_to_face_map = coarse_mesh.corner_to_face_map();
subdiv_ccg_alloc_elements(*subdiv_ccg, subdiv);
subdiv_ccg_alloc_elements(*subdiv_ccg, subdiv, settings);
subdiv_ccg_init_faces_neighborhood(*subdiv_ccg);
if (!subdiv_ccg_evaluate_grids(*subdiv_ccg, subdiv, mask_evaluator)) {
stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
@@ -533,24 +470,26 @@ SubdivCCG::~SubdivCCG()
}
}
CCGKey BKE_subdiv_ccg_key(const SubdivCCG &subdiv_ccg, int level)
CCGKey BKE_subdiv_ccg_key(const SubdivCCG & /*subdiv_ccg*/, int level)
{
#ifdef WITH_OPENSUBDIV
/* Most #CCGKey fields are unused for #SubdivCCG but still used in other areas of Blender.
* Initialize them to invalid values to catch mistaken use more easily. */
CCGKey key;
key.level = level;
key.elem_size = element_size_bytes_get(subdiv_ccg);
key.elem_size = -1;
key.grid_size = grid_size_from_level(level);
key.grid_area = key.grid_size * key.grid_size;
key.grid_bytes = key.elem_size * key.grid_area;
key.grid_bytes = -1;
key.normal_offset = subdiv_ccg.normal_offset;
key.mask_offset = subdiv_ccg.mask_offset;
key.normal_offset = -1;
key.mask_offset = -1;
key.has_normals = subdiv_ccg.has_normal;
key.has_mask = subdiv_ccg.has_mask;
key.has_normals = false;
key.has_mask = false;
return key;
#else
UNUSED_VARS(subdiv_ccg, level);
UNUSED_VARS(level);
return {};
#endif
}
@@ -574,41 +513,36 @@ CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
*
* The result is stored in normals storage from TLS. */
static void subdiv_ccg_recalc_inner_face_normals(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
MutableSpan<float3> face_normals,
const int corner)
{
const int grid_size = subdiv_ccg.grid_size;
const int grid_area = subdiv_ccg.grid_area;
const int grid_size_1 = grid_size - 1;
CCGElem *grid = subdiv_ccg.grids[corner];
const Span grid_positions = subdiv_ccg.positions.as_span().slice(grid_range(grid_area, corner));
for (int y = 0; y < grid_size - 1; y++) {
for (int x = 0; x < grid_size - 1; x++) {
CCGElem *grid_elements[4] = {
CCG_grid_elem(key, grid, x, y + 1),
CCG_grid_elem(key, grid, x + 1, y + 1),
CCG_grid_elem(key, grid, x + 1, y),
CCG_grid_elem(key, grid, x, y),
};
const int face_index = y * grid_size_1 + x;
float *face_normal = face_normals[face_index];
normal_quad_v3(face_normal,
CCG_elem_co(key, grid_elements[0]),
CCG_elem_co(key, grid_elements[1]),
CCG_elem_co(key, grid_elements[2]),
CCG_elem_co(key, grid_elements[3]));
grid_positions[CCG_grid_xy_to_index(grid_size, x, y + 1)],
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y + 1)],
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y)],
grid_positions[CCG_grid_xy_to_index(grid_size, x, y)]);
}
}
}
/* Average normals at every grid element, using adjacent faces normals. */
static void subdiv_ccg_average_inner_face_normals(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
static void subdiv_ccg_average_inner_face_normals(SubdivCCG &subdiv_ccg,
const Span<float3> face_normals,
const int corner)
{
const int grid_size = subdiv_ccg.grid_size;
const int grid_area = subdiv_ccg.grid_area;
const int grid_size_1 = grid_size - 1;
CCGElem *grid = subdiv_ccg.grids[corner];
MutableSpan grid_normals = subdiv_ccg.normals.as_mutable_span().slice(
grid_range(grid_area, corner));
for (int y = 0; y < grid_size; y++) {
for (int x = 0; x < grid_size; x++) {
float normal_acc[3] = {0.0f, 0.0f, 0.0f};
@@ -633,7 +567,7 @@ static void subdiv_ccg_average_inner_face_normals(const SubdivCCG &subdiv_ccg,
counter++;
}
/* Normalize and store. */
mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y), normal_acc, 1.0f / counter);
mul_v3_v3fl(grid_normals[CCG_grid_xy_to_index(grid_size, x, y)], normal_acc, 1.0f / counter);
}
}
}
@@ -654,8 +588,8 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG &subdiv_ccg, const In
for (const int face_index : segment) {
const IndexRange face = faces[face_index];
for (const int grid_index : face) {
subdiv_ccg_recalc_inner_face_normals(subdiv_ccg, key, face_normals, grid_index);
subdiv_ccg_average_inner_face_normals(subdiv_ccg, key, face_normals, grid_index);
subdiv_ccg_recalc_inner_face_normals(subdiv_ccg, face_normals, grid_index);
subdiv_ccg_average_inner_face_normals(subdiv_ccg, face_normals, grid_index);
}
subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
@@ -667,7 +601,7 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG &subdiv_ccg, const In
void BKE_subdiv_ccg_recalc_normals(SubdivCCG &subdiv_ccg)
{
#ifdef WITH_OPENSUBDIV
if (!subdiv_ccg.has_normal) {
if (subdiv_ccg.normals.is_empty()) {
/* Grids don't have normals, can do early output. */
return;
}
@@ -681,7 +615,7 @@ void BKE_subdiv_ccg_recalc_normals(SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
{
#ifdef WITH_OPENSUBDIV
if (!subdiv_ccg.has_normal) {
if (subdiv_ccg.normals.is_empty()) {
/* Grids don't have normals, can do early output. */
return;
}
@@ -713,21 +647,20 @@ static void average_grid_element_value_v3(float a[3], float b[3])
copy_v3_v3(b, a);
}
static void average_grid_element(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
CCGElem *grid_element_a,
CCGElem *grid_element_b)
static void average_grid_element(SubdivCCG &subdiv_ccg,
const int grid_element_a,
const int 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));
average_grid_element_value_v3(subdiv_ccg.positions[grid_element_a],
subdiv_ccg.positions[grid_element_b]);
if (!subdiv_ccg.normals.is_empty()) {
average_grid_element_value_v3(subdiv_ccg.normals[grid_element_a],
subdiv_ccg.normals[grid_element_b]);
}
if (subdiv_ccg.has_mask) {
float mask = (CCG_elem_mask(key, grid_element_a) + CCG_elem_mask(key, grid_element_b)) * 0.5f;
CCG_elem_mask(key, grid_element_a) = mask;
CCG_elem_mask(key, grid_element_b) = mask;
if (!subdiv_ccg.masks.is_empty()) {
float mask = (subdiv_ccg.masks[grid_element_a] + subdiv_ccg.masks[grid_element_b]) * 0.5f;
subdiv_ccg.masks[grid_element_a] = mask;
subdiv_ccg.masks[grid_element_b] = mask;
}
}
@@ -747,15 +680,14 @@ static void element_accumulator_init(GridElementAccumulator &accumulator)
static void element_accumulator_add(GridElementAccumulator &accumulator,
const SubdivCCG &subdiv_ccg,
const CCGKey &key,
/*const*/ CCGElem &grid_element)
const int elem)
{
accumulator.co += CCG_elem_co(key, &grid_element);
if (subdiv_ccg.has_normal) {
accumulator.no += CCG_elem_no(key, &grid_element);
accumulator.co += subdiv_ccg.positions[elem];
if (!subdiv_ccg.normals.is_empty()) {
accumulator.no += subdiv_ccg.normals[elem];
}
if (subdiv_ccg.has_mask) {
accumulator.mask += CCG_elem_mask(key, &grid_element);
if (!subdiv_ccg.masks.is_empty()) {
accumulator.mask += subdiv_ccg.masks[elem];
}
}
@@ -766,17 +698,16 @@ static void element_accumulator_mul_fl(GridElementAccumulator &accumulator, cons
accumulator.mask *= f;
}
static void element_accumulator_copy(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
CCGElem &destination,
static void element_accumulator_copy(SubdivCCG &subdiv_ccg,
const int destination,
const GridElementAccumulator &accumulator)
{
CCG_elem_co(key, &destination) = accumulator.co;
if (subdiv_ccg.has_normal) {
CCG_elem_no(key, &destination) = accumulator.no;
subdiv_ccg.positions[destination] = accumulator.co;
if (!subdiv_ccg.normals.is_empty()) {
subdiv_ccg.normals[destination] = accumulator.no;
}
if (subdiv_ccg.has_mask) {
CCG_elem_mask(key, &destination) = accumulator.mask;
if (!subdiv_ccg.masks.is_empty()) {
subdiv_ccg.masks[destination] = accumulator.mask;
}
}
@@ -784,17 +715,15 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
const CCGKey &key,
const IndexRange face)
{
const Span<CCGElem *> grids = subdiv_ccg.grids;
const int num_face_grids = face.size();
const int grid_size = subdiv_ccg.grid_size;
CCGElem *prev_grid = grids[face.start() + num_face_grids - 1];
int prev_grid = face.start() + num_face_grids - 1;
/* Average boundary between neighbor grid. */
for (int corner = 0; corner < num_face_grids; corner++) {
CCGElem *grid = grids[face.start() + corner];
for (const int grid : face) {
for (int i = 1; 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);
const int prev_grid_element = grid_xy_to_vert(key, prev_grid, i, 0);
const int grid_element = grid_xy_to_vert(key, grid, 0, i);
average_grid_element(subdiv_ccg, prev_grid_element, grid_element);
}
prev_grid = grid;
}
@@ -802,16 +731,14 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
* Guarantees correct and smooth averaging in the center. */
GridElementAccumulator center_accumulator;
element_accumulator_init(center_accumulator);
for (int corner = 0; corner < num_face_grids; corner++) {
CCGElem *grid = grids[face.start() + corner];
CCGElem *grid_center_element = CCG_grid_elem(key, grid, 0, 0);
element_accumulator_add(center_accumulator, subdiv_ccg, key, *grid_center_element);
for (const int grid : face) {
const int grid_center_element = grid_xy_to_vert(key, grid, 0, 0);
element_accumulator_add(center_accumulator, subdiv_ccg, grid_center_element);
}
element_accumulator_mul_fl(center_accumulator, 1.0f / num_face_grids);
for (int corner = 0; corner < num_face_grids; corner++) {
CCGElem *grid = grids[face.start() + corner];
CCGElem *grid_center_element = CCG_grid_elem(key, grid, 0, 0);
element_accumulator_copy(subdiv_ccg, key, *grid_center_element, center_accumulator);
for (const int grid : face) {
const int grid_center_element = grid_xy_to_vert(key, grid, 0, 0);
element_accumulator_copy(subdiv_ccg, grid_center_element, center_accumulator);
}
}
@@ -831,9 +758,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG &subdiv_ccg,
}
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
for (int i = 1; i < grid_size2 - 1; i++) {
CCGElem *grid_element = subdiv_ccg_coord_to_elem(
key, subdiv_ccg, adjacent_edge.boundary_coords[face_index][i]);
element_accumulator_add(accumulators[i], subdiv_ccg, key, *grid_element);
const int grid_element = adjacent_edge.boundary_coords[face_index][i].to_index(key);
element_accumulator_add(accumulators[i], subdiv_ccg, grid_element);
}
}
for (int i = 1; i < grid_size2 - 1; i++) {
@@ -842,9 +768,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG &subdiv_ccg,
/* Copy averaged value to all the other faces. */
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
for (int i = 1; i < grid_size2 - 1; i++) {
CCGElem *grid_element = subdiv_ccg_coord_to_elem(
key, subdiv_ccg, adjacent_edge.boundary_coords[face_index][i]);
element_accumulator_copy(subdiv_ccg, key, *grid_element, accumulators[i]);
const int grid_element = adjacent_edge.boundary_coords[face_index][i].to_index(key);
element_accumulator_copy(subdiv_ccg, grid_element, accumulators[i]);
}
}
}
@@ -869,16 +794,14 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG &subdiv_ccg,
GridElementAccumulator accumulator;
element_accumulator_init(accumulator);
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
CCGElem *grid_element = subdiv_ccg_coord_to_elem(
key, subdiv_ccg, adjacent_vertex.corner_coords[face_index]);
element_accumulator_add(accumulator, subdiv_ccg, key, *grid_element);
const int grid_element = adjacent_vertex.corner_coords[face_index].to_index(key);
element_accumulator_add(accumulator, subdiv_ccg, grid_element);
}
element_accumulator_mul_fl(accumulator, 1.0f / num_adjacent_faces);
/* Copy averaged value to all the other faces. */
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
CCGElem *grid_element = subdiv_ccg_coord_to_elem(
key, subdiv_ccg, adjacent_vertex.corner_coords[face_index]);
element_accumulator_copy(subdiv_ccg, key, *grid_element, accumulator);
const int grid_element = adjacent_vertex.corner_coords[face_index].to_index(key);
element_accumulator_copy(subdiv_ccg, grid_element, accumulator);
}
}
@@ -999,7 +922,7 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg,
int &r_num_faces,
int &r_num_loops)
{
const int num_grids = subdiv_ccg.grids.size();
const int num_grids = subdiv_ccg.grids_num;
const int grid_size = subdiv_ccg.grid_size;
const int grid_area = grid_size * grid_size;
const int num_edges_per_grid = 2 * (grid_size * (grid_size - 1));
@@ -1022,7 +945,7 @@ void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord &coord
bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
{
if (coord.grid_index < 0 || coord.grid_index >= subdiv_ccg.grids.size()) {
if (coord.grid_index < 0 || coord.grid_index >= subdiv_ccg.grids_num) {
return false;
}
const int grid_size = subdiv_ccg.grid_size;
@@ -1536,7 +1459,7 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
{
#ifdef WITH_OPENSUBDIV
BLI_assert(coord.grid_index >= 0);
BLI_assert(coord.grid_index < subdiv_ccg.grids.size());
BLI_assert(coord.grid_index < subdiv_ccg.grids_num);
BLI_assert(coord.x >= 0);
BLI_assert(coord.x < subdiv_ccg.grid_size);
BLI_assert(coord.y >= 0);
@@ -1676,8 +1599,8 @@ bool BKE_subdiv_ccg_coord_is_mesh_boundary(const OffsetIndices<int> faces,
blender::BitGroupVector<> &BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg)
{
if (subdiv_ccg.grid_hidden.is_empty()) {
const int grid_area = subdiv_ccg.grid_size * subdiv_ccg.grid_size;
subdiv_ccg.grid_hidden = blender::BitGroupVector<>(subdiv_ccg.grids.size(), grid_area, false);
const int grid_area = subdiv_ccg.grid_area;
subdiv_ccg.grid_hidden = blender::BitGroupVector<>(subdiv_ccg.grids_num, grid_area, false);
}
return subdiv_ccg.grid_hidden;
}

View File

@@ -74,9 +74,7 @@ void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob)
case blender::bke::pbvh::Type::Grids: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Mesh &base_mesh = *static_cast<const Mesh *>(object_orig->data);
if (!BKE_subdiv_ccg_key_top_level(subdiv_ccg).has_mask &&
!base_mesh.attributes().contains(".sculpt_face_set"))
{
if (subdiv_ccg.masks.is_empty() && !base_mesh.attributes().contains(".sculpt_face_set")) {
return;
}
break;

View File

@@ -692,65 +692,64 @@ static void fill_vbo_attribute_mesh(const OffsetIndices<int> faces,
}
static void fill_vbo_position_grids(const CCGKey &key,
const Span<CCGElem *> grids,
const Span<float3> positions,
const bool use_flat_layout,
const Span<int> grid_indices,
const Span<int> grids,
gpu::VertBuf &vert_buf)
{
float3 *data = vert_buf.data<float3>().data();
if (use_flat_layout) {
const int grid_size_1 = key.grid_size - 1;
for (const int i : grid_indices.index_range()) {
CCGElem *grid = grids[grid_indices[i]];
for (const int grid : grids) {
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
for (int y = 0; y < grid_size_1; y++) {
for (int x = 0; x < grid_size_1; x++) {
*data = CCG_grid_elem_co(key, grid, x, y);
*data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y)];
data++;
*data = CCG_grid_elem_co(key, grid, x + 1, y);
*data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y)];
data++;
*data = CCG_grid_elem_co(key, grid, x + 1, y + 1);
*data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y + 1)];
data++;
*data = CCG_grid_elem_co(key, grid, x, y + 1);
*data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y + 1)];
data++;
}
}
}
}
else {
for (const int i : grid_indices.index_range()) {
CCGElem *grid = grids[grid_indices[i]];
for (const int offset : IndexRange(key.grid_area)) {
*data = CCG_elem_offset_co(key, grid, offset);
data++;
}
for (const int grid : grids) {
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
std::copy_n(grid_positions.data(), grid_positions.size(), data);
data += grid_positions.size();
}
}
}
static void fill_vbo_normal_grids(const CCGKey &key,
const Span<CCGElem *> grids,
const Span<float3> positions,
const Span<float3> normals,
const Span<int> grid_to_face_map,
const Span<bool> sharp_faces,
const bool use_flat_layout,
const Span<int> grid_indices,
const Span<int> grids,
gpu::VertBuf &vert_buf)
{
short4 *data = vert_buf.data<short4>().data();
if (use_flat_layout) {
const int grid_size_1 = key.grid_size - 1;
for (const int i : grid_indices.index_range()) {
const int grid_index = grid_indices[i];
CCGElem *grid = grids[grid_index];
if (!sharp_faces.is_empty() && sharp_faces[grid_to_face_map[grid_index]]) {
for (const int grid : grids) {
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
const Span<float3> grid_normals = normals.slice(bke::ccg::grid_range(key, grid));
if (!sharp_faces.is_empty() && sharp_faces[grid_to_face_map[grid]]) {
for (int y = 0; y < grid_size_1; y++) {
for (int x = 0; x < grid_size_1; x++) {
float3 no;
normal_quad_v3(no,
CCG_grid_elem_co(key, grid, x, y + 1),
CCG_grid_elem_co(key, grid, x + 1, y + 1),
CCG_grid_elem_co(key, grid, x + 1, y),
CCG_grid_elem_co(key, grid, x, y));
grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y + 1)],
grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y + 1)],
grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y)],
grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y)]);
std::fill_n(data, 4, normal_float_to_short(no));
data += 4;
}
@@ -759,7 +758,10 @@ static void fill_vbo_normal_grids(const CCGKey &key,
else {
for (int y = 0; y < grid_size_1; y++) {
for (int x = 0; x < grid_size_1; x++) {
std::fill_n(data, 4, normal_float_to_short(CCG_grid_elem_no(key, grid, x, y)));
std::fill_n(
data,
4,
normal_float_to_short(grid_normals[CCG_grid_xy_to_index(key.grid_size, x, y)]));
data += 4;
}
}
@@ -768,10 +770,9 @@ static void fill_vbo_normal_grids(const CCGKey &key,
}
else {
/* The non-flat VBO layout does not support sharp faces. */
for (const int i : grid_indices.index_range()) {
CCGElem *grid = grids[grid_indices[i]];
for (const int offset : IndexRange(key.grid_area)) {
*data = normal_float_to_short(CCG_elem_offset_no(key, grid, offset));
for (const int grid : grids) {
for (const float3 &normal : normals.slice(bke::ccg::grid_range(key, grid))) {
*data = normal_float_to_short(normal);
data++;
}
}
@@ -779,43 +780,36 @@ static void fill_vbo_normal_grids(const CCGKey &key,
}
static void fill_vbo_mask_grids(const CCGKey &key,
const Span<CCGElem *> grids,
const Span<float> masks,
const bool use_flat_layout,
const Span<int> grid_indices,
const Span<int> grids,
gpu::VertBuf &vert_buf)
{
if (key.has_mask) {
float *data = vert_buf.data<float>().data();
if (use_flat_layout) {
const int grid_size_1 = key.grid_size - 1;
for (const int i : grid_indices.index_range()) {
CCGElem *grid = grids[grid_indices[i]];
for (int y = 0; y < grid_size_1; y++) {
for (int x = 0; x < grid_size_1; x++) {
*data = CCG_grid_elem_mask(key, grid, x, y);
data++;
*data = CCG_grid_elem_mask(key, grid, x + 1, y);
data++;
*data = CCG_grid_elem_mask(key, grid, x + 1, y + 1);
data++;
*data = CCG_grid_elem_mask(key, grid, x, y + 1);
data++;
}
}
}
}
else {
for (const int i : grid_indices.index_range()) {
CCGElem *grid = grids[grid_indices[i]];
for (const int offset : IndexRange(key.grid_area)) {
*data = CCG_elem_offset_mask(key, grid, offset);
float *data = vert_buf.data<float>().data();
if (use_flat_layout) {
const int grid_size_1 = key.grid_size - 1;
for (const int grid : grids) {
const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
for (int y = 0; y < grid_size_1; y++) {
for (int x = 0; x < grid_size_1; x++) {
*data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x, y)];
data++;
*data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x + 1, y)];
data++;
*data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x + 1, y + 1)];
data++;
*data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x, y + 1)];
data++;
}
}
}
}
else {
vert_buf.data<float>().fill(0.0f);
for (const int grid : grids) {
const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
std::copy_n(grid_masks.data(), grid_masks.size(), data);
data += grid_masks.size();
}
}
}
@@ -855,13 +849,13 @@ static void fill_vbos_grids(const Object &object,
const Span<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&request)) {
switch (*request_type) {
case CustomRequest::Position: {
node_mask.foreach_index(GrainSize(1), [&](const int i) {
fill_vbo_position_grids(key, grids, use_flat_layout[i], nodes[i].grids(), *vbos[i]);
fill_vbo_position_grids(
key, subdiv_ccg.positions, use_flat_layout[i], nodes[i].grids(), *vbos[i]);
});
break;
}
@@ -872,7 +866,8 @@ static void fill_vbos_grids(const Object &object,
bke::AttrDomain::Face);
node_mask.foreach_index(GrainSize(1), [&](const int i) {
fill_vbo_normal_grids(key,
grids,
subdiv_ccg.positions,
subdiv_ccg.normals,
grid_to_face_map,
sharp_faces,
use_flat_layout[i],
@@ -883,9 +878,16 @@ static void fill_vbos_grids(const Object &object,
break;
}
case CustomRequest::Mask: {
node_mask.foreach_index(GrainSize(1), [&](const int i) {
fill_vbo_mask_grids(key, grids, use_flat_layout[i], nodes[i].grids(), *vbos[i]);
});
const Span<float> masks = subdiv_ccg.masks;
if (!masks.is_empty()) {
node_mask.foreach_index(GrainSize(1), [&](const int i) {
fill_vbo_mask_grids(key, masks, use_flat_layout[i], nodes[i].grids(), *vbos[i]);
});
}
else {
node_mask.foreach_index(GrainSize(64),
[&](const int i) { vbos[i]->data<float>().fill(0.0f); });
}
break;
}
case CustomRequest::FaceSet: {

View File

@@ -205,7 +205,7 @@ static void calc_translations_grids(const SubdivCCG &subdiv_ccg,
tls.new_positions.resize(positions.size());
const MutableSpan<float3> new_positions = tls.new_positions;
smooth::neighbor_position_average_grids(subdiv_ccg, grids, new_positions);
smooth::average_data_grids(subdiv_ccg, subdiv_ccg.positions.as_span(), grids, new_positions);
tls.translations.resize(positions.size());
const MutableSpan<float3> translations = tls.translations;

View File

@@ -43,7 +43,7 @@ static void calc_node(const Depsgraph &depsgraph,
SculptSession &ss = *object.sculpt;
const StrokeCache &cache = *ss.cache;
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Span<CCGElem *> elems = subdiv_ccg.grids;
MutableSpan<float3> ccg_positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<int> grids = node.grids();
@@ -73,7 +73,6 @@ static void calc_node(const Depsgraph &depsgraph,
const int node_start = i * key.grid_area;
const int grid = grids[i];
const int start = grid * key.grid_area;
CCGElem *elem = elems[grid];
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
@@ -134,7 +133,7 @@ static void calc_node(const Depsgraph &depsgraph,
float3 new_co = cache.displacement_smear.limit_surface_co[grid_vert_index] +
interp_limit_surface_disp;
CCG_elem_offset_co(key, elem, offset) = math::interpolate(
ccg_positions[grid_vert_index] = math::interpolate(
positions[node_vert_index], new_co, factors[node_vert_index]);
}
}
@@ -145,26 +144,24 @@ BLI_NOINLINE static void eval_all_limit_positions(const SubdivCCG &subdiv_ccg,
const MutableSpan<float3> limit_positions)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
threading::parallel_for(subdiv_ccg.grids.index_range(), 1024, [&](const IndexRange range) {
threading::parallel_for(IndexRange(subdiv_ccg.grids_num), 1024, [&](const IndexRange range) {
for (const int grid : range) {
const MutableSpan grid_limit_positions = limit_positions.slice(grid * key.grid_area,
key.grid_area);
const MutableSpan grid_limit_positions = limit_positions.slice(
bke::ccg::grid_range(key.grid_area, grid));
BKE_subdiv_ccg_eval_limit_positions(subdiv_ccg, key, grid, grid_limit_positions);
}
});
}
BLI_NOINLINE static void store_node_prev_displacement(const Span<float3> limit_positions,
const Span<CCGElem *> elems,
const Span<float3> positions,
const CCGKey &key,
const bke::pbvh::GridsNode &node,
const MutableSpan<float3> prev_displacement)
{
for (const int grid : node.grids()) {
const int start = grid * key.grid_area;
CCGElem *elem = elems[grid];
for (const int i : IndexRange(key.grid_area)) {
prev_displacement[start + i] = CCG_elem_offset_co(key, elem, i) - limit_positions[start + i];
for (const int i : bke::ccg::grid_range(key.grid_area, grid)) {
prev_displacement[i] = positions[i] - limit_positions[i];
}
}
}
@@ -182,12 +179,12 @@ void do_displacement_smear_brush(const Depsgraph &depsgraph,
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Span<CCGElem *> elems = subdiv_ccg.grids;
MutableSpan<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (ss.cache->displacement_smear.limit_surface_co.is_empty()) {
ss.cache->displacement_smear.prev_displacement = Array<float3>(elems.size() * key.grid_area);
ss.cache->displacement_smear.limit_surface_co = Array<float3>(elems.size() * key.grid_area);
ss.cache->displacement_smear.prev_displacement = Array<float3>(positions.size());
ss.cache->displacement_smear.limit_surface_co = Array<float3>(positions.size());
eval_all_limit_positions(subdiv_ccg, ss.cache->displacement_smear.limit_surface_co);
}
@@ -195,7 +192,7 @@ void do_displacement_smear_brush(const Depsgraph &depsgraph,
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
node_mask.slice(range).foreach_index([&](const int i) {
store_node_prev_displacement(ss.cache->displacement_smear.limit_surface_co,
elems,
subdiv_ccg.positions,
key,
nodes[i],
ss.cache->displacement_smear.prev_displacement);

View File

@@ -226,13 +226,13 @@ BLI_NOINLINE static void calc_factors_grids(const Depsgraph &depsgraph,
{
SculptSession &ss = *object.sculpt;
const StrokeCache &cache = *ss.cache;
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<int> grids = node.grids();
const int grid_verts_num = grids.size() * key.grid_area;
gather_grids_positions(key, subdiv_ccg.grids, grids, positions);
gather_data_grids(subdiv_ccg, subdiv_ccg.positions.as_span(), grids, positions);
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
filter_region_clip_factors(ss, positions, factors);
@@ -319,7 +319,6 @@ static void do_relax_face_sets_brush_grids(const Depsgraph &depsgraph,
nodes[i].grids(),
relax_face_sets,
factors.as_span().slice(node_vert_offsets[pos]),
current_positions.as_span().slice(node_vert_offsets[pos]),
tls.vert_neighbors,
translations.as_mutable_span().slice(node_vert_offsets[pos]));
});
@@ -549,7 +548,7 @@ BLI_NOINLINE static void calc_topology_relax_factors_grids(const Depsgraph &deps
const Span<int> grids = node.grids();
const int grid_verts_num = grids.size() * key.grid_area;
gather_grids_positions(key, subdiv_ccg.grids, grids, positions);
gather_data_grids(subdiv_ccg, subdiv_ccg.positions.as_span(), grids, positions);
const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
@@ -626,7 +625,6 @@ static void do_topology_relax_brush_grids(const Depsgraph &depsgraph,
nodes[i].grids(),
false,
factors.as_span().slice(node_vert_offsets[pos]),
current_positions.as_span().slice(node_vert_offsets[pos]),
tls.vert_neighbors,
translations.as_mutable_span().slice(node_vert_offsets[pos]));
});

View File

@@ -221,7 +221,7 @@ static void calc_grids(const Depsgraph &depsgraph,
tls.new_masks.resize(positions.size());
const MutableSpan<float> new_masks = tls.new_masks;
mask::average_neighbor_mask_grids(subdiv_ccg, grids, new_masks);
smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_masks);
mask::mix_new_masks(new_masks, factors, masks);
mask::clamp_mask(masks);

View File

@@ -222,7 +222,8 @@ BLI_NOINLINE static void do_surface_smooth_brush_grids(
tls.average_positions.resize(positions.size());
const MutableSpan<float3> average_positions = tls.average_positions;
smooth::neighbor_position_average_grids(subdiv_ccg, grids, average_positions);
smooth::average_data_grids(
subdiv_ccg, subdiv_ccg.positions.as_span(), grids, average_positions);
tls.laplacian_disp.resize(positions.size());
const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;

View File

@@ -91,22 +91,23 @@ BLI_NOINLINE static void calc_neighbor_influence(const Span<float3> vert_positio
}
BLI_NOINLINE static void calc_neighbor_influence(const SubdivCCG &subdiv_ccg,
const Span<float3> positions,
const Span<int> grids,
const MutableSpan<float3> translations)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
for (const int i : grids.index_range()) {
const int node_start = i * key.grid_area;
const int grid = grids[i];
const int start = grid * key.grid_area;
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert_index = node_start + offset;
const int vert = start + offset;
const int node_vert = node_start + offset;
const float3 &position = positions[node_vert_index];
const float3 &dir = translations[node_vert_index];
const float3 &position = positions[vert];
const float3 &dir = translations[node_vert];
SubdivCCGCoord coord{};
coord.grid_index = grid;
@@ -119,13 +120,10 @@ BLI_NOINLINE static void calc_neighbor_influence(const SubdivCCG &subdiv_ccg,
float3 final_translation(0);
for (const SubdivCCGCoord neighbor : neighbors.coords) {
add_neighbor_influence(
position,
dir,
CCG_grid_elem_co(key, elems[neighbor.grid_index], neighbor.x, neighbor.y),
final_translation);
position, dir, positions[neighbor.to_index(key)], final_translation);
}
translations[node_vert_index] = final_translation;
translations[node_vert] = final_translation;
}
}
}
@@ -247,7 +245,7 @@ static void calc_grids(const Depsgraph &depsgraph,
tls.translations.resize(positions.size());
const MutableSpan<float3> translations = tls.translations;
calc_translation_directions(brush, cache, positions, translations);
calc_neighbor_influence(subdiv_ccg, positions, grids, translations);
calc_neighbor_influence(subdiv_ccg, grids, translations);
scale_translations(translations, factors);
clip_and_lock_translations(sd, ss, orig_data.positions, translations);

View File

@@ -137,17 +137,13 @@ void scatter_data_bmesh(Span<T> node_data, const Set<BMVert *, 0> &verts, Mutabl
*/
/** Fill the output array with all positions in the geometry referenced by the indices. */
void gather_grids_positions(const CCGKey &key,
Span<CCGElem *> elems,
Span<int> grids,
MutableSpan<float3> positions);
inline MutableSpan<float3> gather_grids_positions(const SubdivCCG &subdiv_ccg,
const Span<int> grids,
Vector<float3> &positions)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
positions.resize(key.grid_area * grids.size());
gather_grids_positions(key, subdiv_ccg.grids, grids, positions);
gather_data_grids(subdiv_ccg, subdiv_ccg.positions.as_span(), grids, positions);
return positions;
}
void gather_bmesh_positions(const Set<BMVert *, 0> &verts, MutableSpan<float3> positions);

View File

@@ -574,8 +574,8 @@ static void partialvis_masked_update_grids(Depsgraph &depsgraph,
const bool value = action_to_hide(action);
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
if (!key.has_mask) {
const Span<float> masks = subdiv_ccg.masks;
if (masks.is_empty()) {
grid_hide_update(depsgraph,
object,
node_mask,
@@ -583,14 +583,11 @@ static void partialvis_masked_update_grids(Depsgraph &depsgraph,
}
else {
grid_hide_update(
depsgraph, object, node_mask, [&](const int grid_index, MutableBoundedBitSpan hide) {
CCGElem *grid = grids[grid_index];
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
if (CCG_elem_mask(key, elem) > 0.5f) {
hide[y * key.grid_size + x].set(value);
}
depsgraph, object, node_mask, [&](const int grid, MutableBoundedBitSpan hide) {
const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
for (const int i : grid_masks.index_range()) {
if (grid_masks[i] > 0.5f) {
hide[i].set(value);
}
}
});
@@ -1236,20 +1233,17 @@ static void partialvis_gesture_update_grids(Depsgraph &depsgraph,
const bool value = action_to_hide(action);
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
grid_hide_update(
depsgraph, *object, node_mask, [&](const int grid_index, MutableBoundedBitSpan hide) {
CCGElem *grid = grids[grid_index];
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
if (gesture::is_affected(gesture_data, CCG_elem_co(key, elem), CCG_elem_no(key, elem)))
{
hide[y * key.grid_size + x].set(value);
}
}
}
});
const Span<float3> positions = subdiv_ccg.positions;
const Span<float3> normals = subdiv_ccg.normals;
grid_hide_update(depsgraph, *object, node_mask, [&](const int grid, MutableBoundedBitSpan hide) {
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
const Span<float3> grid_normals = normals.slice(bke::ccg::grid_range(key, grid));
for (const int i : grid_positions.index_range()) {
if (gesture::is_affected(gesture_data, grid_positions[i], grid_normals[i])) {
hide[i].set(value);
}
}
});
}
static void partialvis_gesture_update_bmesh(gesture::GestureData &gesture_data)

View File

@@ -69,19 +69,10 @@ Array<float> duplicate_mask(const Object &object)
}
case bke::pbvh::Type::Grids: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
Array<float> result(grids.size() * key.grid_area);
int index = 0;
for (const int grid : grids.index_range()) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
result[index] = CCG_elem_offset_mask(key, elem, i);
index++;
}
if (subdiv_ccg.masks.is_empty()) {
return Array<float>(subdiv_ccg.positions.size(), 0.0f);
}
return result;
return subdiv_ccg.masks;
}
case bke::pbvh::Type::BMesh: {
BMesh &bm = *ss.bm;
@@ -141,18 +132,8 @@ void gather_mask_grids(const SubdivCCG &subdiv_ccg,
const Span<int> grids,
const MutableSpan<float> r_mask)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
BLI_assert(grids.size() * key.grid_area == r_mask.size());
if (key.has_mask) {
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
r_mask[start + offset] = CCG_elem_offset_mask(key, elem, offset);
}
}
if (!subdiv_ccg.masks.is_empty()) {
gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, r_mask);
}
else {
r_mask.fill(0.0f);
@@ -161,17 +142,7 @@ void gather_mask_grids(const SubdivCCG &subdiv_ccg,
void scatter_mask_grids(const Span<float> mask, SubdivCCG &subdiv_ccg, const Span<int> grids)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
BLI_assert(key.has_mask);
BLI_assert(mask.size() == grids.size() * key.grid_area);
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
CCG_elem_offset_mask(key, elem, offset) = mask[start + offset];
}
}
scatter_data_grids(subdiv_ccg, mask, grids, subdiv_ccg.masks.as_mutable_span());
}
void scatter_mask_bmesh(const Span<float> mask, const BMesh &bm, const Set<BMVert *, 0> &verts)
@@ -187,47 +158,6 @@ void scatter_mask_bmesh(const Span<float> mask, const BMesh &bm, const Set<BMVer
}
}
static float average_masks(const CCGKey &key,
const Span<CCGElem *> elems,
const Span<SubdivCCGCoord> coords)
{
float sum = 0;
for (const SubdivCCGCoord coord : coords) {
sum += CCG_grid_elem_mask(key, elems[coord.grid_index], coord.x, coord.y);
}
return sum / float(coords.size());
}
void average_neighbor_mask_grids(const SubdivCCG &subdiv_ccg,
const Span<int> grids,
const MutableSpan<float> new_masks)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
for (const int i : grids.index_range()) {
const int grid = grids[i];
const int node_verts_start = i * key.grid_area;
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert_index = node_verts_start + offset;
SubdivCCGCoord coord{};
coord.grid_index = grid;
coord.x = x;
coord.y = y;
SubdivCCGNeighbors neighbors;
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
new_masks[node_vert_index] = average_masks(key, elems, neighbors.coords);
}
}
}
}
static float average_masks(const int mask_offset, const Span<const BMVert *> verts)
{
float sum = 0;
@@ -292,7 +222,7 @@ void update_mask_mesh(const Depsgraph &depsgraph,
mask.finish();
}
bool mask_equals_array_grids(const Span<CCGElem *> elems,
bool mask_equals_array_grids(const Span<float> masks,
const CCGKey &key,
const Span<int> grids,
const Span<float> values)
@@ -301,15 +231,8 @@ bool mask_equals_array_grids(const Span<CCGElem *> elems,
const IndexRange range = grids.index_range();
return std::all_of(range.begin(), range.end(), [&](const int i) {
const int grid = grids[i];
const int node_verts_start = i * key.grid_area;
CCGElem *elem = elems[grid];
for (const int offset : IndexRange(key.grid_area)) {
if (CCG_elem_offset_mask(key, elem, i) != values[node_verts_start + offset]) {
return false;
}
}
return masks.slice(bke::ccg::grid_range(key, grids[i])) ==
values.slice(bke::ccg::grid_range(key, i));
return true;
});
}
@@ -502,8 +425,8 @@ static void fill_mask_grids(Main &bmain,
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (value == 0.0f && !key.has_mask) {
/* Unlike meshes, don't dynamically remove masks since it is interleaved with other data. */
if (value == 0.0f && subdiv_ccg.masks.is_empty()) {
/* NOTE: Deleting the mask array would be possible here. */
return;
}
@@ -512,18 +435,15 @@ static void fill_mask_grids(Main &bmain,
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const Span<CCGElem *> grids = subdiv_ccg.grids;
MutableSpan<float> masks = subdiv_ccg.masks;
bool any_changed = false;
node_mask.foreach_index(GrainSize(1), [&](const int i) {
const Span<int> grid_indices = nodes[i].grids();
if (std::all_of(grid_indices.begin(), grid_indices.end(), [&](const int grid) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
if (CCG_elem_offset_mask(key, elem, i) != value) {
return false;
}
}
return true;
const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
return std::all_of(grid_masks.begin(), grid_masks.end(), [&](const float mask) {
return mask == value;
});
}))
{
return;
@@ -532,17 +452,13 @@ static void fill_mask_grids(Main &bmain,
if (grid_hidden.is_empty()) {
for (const int grid : grid_indices) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
CCG_elem_offset_mask(key, elem, i) = value;
}
masks.slice(bke::ccg::grid_range(key, grid)).fill(value);
}
}
else {
for (const int grid : grid_indices) {
CCGElem *elem = grids[grid];
bits::foreach_0_index(grid_hidden[grid],
[&](const int i) { CCG_elem_offset_mask(key, elem, i) = value; });
MutableSpan<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
bits::foreach_0_index(grid_hidden[grid], [&](const int i) { grid_masks[i] = value; });
}
}
BKE_pbvh_node_mark_redraw(nodes[i]);
@@ -640,27 +556,25 @@ static void invert_mask_grids(Main &bmain,
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
MutableSpan<float> masks = subdiv_ccg.masks;
node_mask.foreach_index(GrainSize(1), [&](const int i) {
const Span<int> grid_indices = nodes[i].grids();
if (grid_hidden.is_empty()) {
for (const int grid : grid_indices) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
CCG_elem_offset_mask(key, elem, i) = 1.0f - CCG_elem_offset_mask(key, elem, i);
for (float &value : masks.slice(bke::ccg::grid_range(key, grid))) {
value = 1.0f - value;
}
}
}
else {
for (const int grid : grid_indices) {
CCGElem *elem = grids[grid];
bits::foreach_0_index(grid_hidden[grid], [&](const int i) {
CCG_elem_offset_mask(key, elem, i) = 1.0f - CCG_elem_offset_mask(key, elem, i);
});
MutableSpan<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
bits::foreach_0_index(grid_hidden[grid],
[&](const int i) { grid_masks[i] = 1.0f - grid_masks[i]; });
}
}
BKE_pbvh_node_mark_update_mask(nodes[i]);
bke::pbvh::node_update_mask_grids(key, grids, nodes[i]);
bke::pbvh::node_update_mask_grids(key, masks, nodes[i]);
});
multires_mark_as_modified(&depsgraph, &object, MULTIRES_COORDS_MODIFIED);
@@ -832,20 +746,20 @@ static void gesture_apply_for_symmetry_pass(bContext & /*C*/, gesture::GestureDa
bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
SubdivCCG &subdiv_ccg = *gesture_data.ss->subdiv_ccg;
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const Span<float3> normals = subdiv_ccg.normals;
MutableSpan<float> masks = subdiv_ccg.masks;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
node_mask.slice(range).foreach_index([&](const int i) {
bool any_changed = false;
for (const int grid : nodes[i].grids()) {
CCGElem *elem = grids[grid];
const int vert_start = grid * key.grid_area;
BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int i) {
if (gesture::is_affected(gesture_data,
CCG_elem_offset_co(key, elem, i),
CCG_elem_offset_no(key, elem, i)))
{
float &mask = CCG_elem_offset_mask(key, elem, i);
const int vert = vert_start + i;
if (gesture::is_affected(gesture_data, positions[vert], normals[vert])) {
float &mask = masks[vert];
if (!any_changed) {
any_changed = true;
undo::push_node(depsgraph, object, &nodes[i], undo::Type::Mask);

View File

@@ -15,7 +15,6 @@
struct BMesh;
struct BMVert;
struct CCGElem;
struct CCGKey;
struct Depsgraph;
struct Object;
@@ -37,9 +36,6 @@ void gather_mask_bmesh(const BMesh &bm, const Set<BMVert *, 0> &verts, MutableSp
void scatter_mask_grids(Span<float> mask, SubdivCCG &subdiv_ccg, Span<int> grids);
void scatter_mask_bmesh(Span<float> mask, const BMesh &bm, const Set<BMVert *, 0> &verts);
void average_neighbor_mask_grids(const SubdivCCG &subdiv_ccg,
Span<int> grids,
MutableSpan<float> new_masks);
void average_neighbor_mask_bmesh(int mask_offset,
const Set<BMVert *, 0> &verts,
MutableSpan<float> new_masks);
@@ -60,7 +56,7 @@ void update_mask_mesh(const Depsgraph &depsgraph,
FunctionRef<void(MutableSpan<float>, Span<int>)> update_fn);
/** Check whether array data is the same as the stored mask for the referenced geometry. */
bool mask_equals_array_grids(Span<CCGElem *> elems,
bool mask_equals_array_grids(Span<float> masks,
const CCGKey &key,
Span<int> grids,
Span<float> values);

View File

@@ -176,11 +176,8 @@ const float *SCULPT_vertex_co_get(const Depsgraph &depsgraph,
case blender::bke::pbvh::Type::BMesh:
return ((BMVert *)vertex.i)->co;
case blender::bke::pbvh::Type::Grids: {
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
const int grid_index = vertex.i / key.grid_area;
const int index_in_grid = vertex.i - grid_index * key.grid_area;
CCGElem *elem = ss.subdiv_ccg->grids[grid_index];
return CCG_elem_co(key, CCG_elem_offset(key, elem, index_in_grid));
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
return subdiv_ccg.positions[vertex.i];
}
}
return nullptr;
@@ -201,11 +198,8 @@ const blender::float3 SCULPT_vertex_normal_get(const Depsgraph &depsgraph,
return v->no;
}
case blender::bke::pbvh::Type::Grids: {
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
const int grid_index = vertex.i / key.grid_area;
const int index_in_grid = vertex.i - grid_index * key.grid_area;
CCGElem *elem = ss.subdiv_ccg->grids[grid_index];
return CCG_elem_no(key, CCG_elem_offset(key, elem, index_in_grid));
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
return subdiv_ccg.normals[vertex.i];
}
}
BLI_assert_unreachable();
@@ -913,7 +907,7 @@ std::optional<SubdivCCGCoord> nearest_vert_calc_grids(const bke::pbvh::Tree &pbv
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const Span<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
const NearestData nearest = threading::parallel_reduce(
@@ -923,10 +917,9 @@ std::optional<SubdivCCGCoord> nearest_vert_calc_grids(const bke::pbvh::Tree &pbv
[&](const IndexRange range, NearestData nearest) {
nodes_in_sphere.slice(range).foreach_index([&](const int i) {
for (const int grid : nodes[i].grids()) {
CCGElem *elem = elems[grid];
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int i) {
const float distance_sq = math::distance_squared(CCG_elem_offset_co(key, elem, i),
location);
const float distance_sq = math::distance_squared(positions[grid_range[i]], location);
if (distance_sq < nearest.distance_sq) {
SubdivCCGCoord coord{};
coord.grid_index = grid;
@@ -1218,17 +1211,17 @@ static void restore_mask_from_undo_step(Object &object)
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
MutableSpan<float> masks = subdiv_ccg.masks;
node_mask.foreach_index(GrainSize(1), [&](const int i) {
if (const std::optional<Span<float>> orig_data = orig_mask_data_lookup_grids(object,
nodes[i]))
{
int index = 0;
for (const int grid : nodes[i].grids()) {
CCGElem *elem = grids[grid];
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
for (const int i : IndexRange(key.grid_area)) {
if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
CCG_elem_offset_mask(key, elem, i) = (*orig_data)[index];
masks[grid_range[i]] = (*orig_data)[index];
}
index++;
}
@@ -1408,17 +1401,17 @@ void restore_position_from_undo_step(const Depsgraph &depsgraph, Object &object)
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
MutableSpan<float3> positions = subdiv_ccg.positions;
node_mask.foreach_index(GrainSize(1), [&](const int i) {
if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(
object, nodes[i]))
{
int index = 0;
for (const int grid : nodes[i].grids()) {
CCGElem *elem = grids[grid];
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
for (const int i : IndexRange(key.grid_area)) {
if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
CCG_elem_offset_co(key, elem, i) = orig_data->positions[index];
positions[grid_range[i]] = orig_data->positions[index];
}
index++;
}
@@ -1801,7 +1794,7 @@ static void calc_area_normal_and_center_node_grids(const Object &object,
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> normals = subdiv_ccg.normals;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const Span<int> grids = node.grids();
@@ -1818,25 +1811,29 @@ static void calc_area_normal_and_center_node_grids(const Object &object,
ss, orig_positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
for (const int i : grids.index_range()) {
const int node_verts_start = i * key.grid_area;
const IndexRange grid_range_node = bke::ccg::grid_range(key, i);
const int grid = grids[i];
for (const int offset : IndexRange(key.grid_area)) {
if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
continue;
}
const int vert = node_verts_start + offset;
const int node_vert = grid_range_node[offset];
const bool normal_test_r = use_area_nos && distances_sq[vert] <= normal_radius_sq;
const bool area_test_r = use_area_cos && distances_sq[vert] <= position_radius_sq;
const bool normal_test_r = use_area_nos && distances_sq[node_vert] <= normal_radius_sq;
const bool area_test_r = use_area_cos && distances_sq[node_vert] <= position_radius_sq;
if (!normal_test_r && !area_test_r) {
continue;
}
const float3 &normal = orig_normals[vert];
const float distance = std::sqrt(distances_sq[vert]);
const float3 &normal = orig_normals[node_vert];
const float distance = std::sqrt(distances_sq[node_vert]);
const int flip_index = math::dot(view_normal, normal) <= 0.0f;
if (area_test_r) {
accumulate_area_center(
location, orig_positions[vert], distance, position_radius_inv, flip_index, anctd);
accumulate_area_center(location,
orig_positions[node_vert],
distance,
position_radius_inv,
flip_index,
anctd);
}
if (normal_test_r) {
accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
@@ -1854,30 +1851,27 @@ static void calc_area_normal_and_center_node_grids(const Object &object,
ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
for (const int i : grids.index_range()) {
const int node_verts_start = i * key.grid_area;
const IndexRange grid_range_node = bke::ccg::grid_range(key, i);
const int grid = grids[i];
CCGElem *elem = elems[grid];
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
for (const int offset : IndexRange(key.grid_area)) {
if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
continue;
}
const int vert = node_verts_start + offset;
const int node_vert = grid_range_node[offset];
const int vert = grid_range[offset];
const bool normal_test_r = use_area_nos && distances_sq[vert] <= normal_radius_sq;
const bool area_test_r = use_area_cos && distances_sq[vert] <= position_radius_sq;
const bool normal_test_r = use_area_nos && distances_sq[node_vert] <= normal_radius_sq;
const bool area_test_r = use_area_cos && distances_sq[node_vert] <= position_radius_sq;
if (!normal_test_r && !area_test_r) {
continue;
}
const float3 &normal = CCG_elem_offset_no(key, elem, offset);
const float distance = std::sqrt(distances_sq[vert]);
const float3 &normal = normals[vert];
const float distance = std::sqrt(distances_sq[node_vert]);
const int flip_index = math::dot(view_normal, normal) <= 0.0f;
if (area_test_r) {
accumulate_area_center(location,
CCG_elem_offset_co(key, elem, offset),
distance,
position_radius_inv,
flip_index,
anctd);
accumulate_area_center(
location, positions[node_vert], distance, position_radius_inv, flip_index, anctd);
}
if (normal_test_r) {
accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
@@ -5981,7 +5975,7 @@ static void fake_neighbor_search_mesh(const SculptSession &ss,
static void fake_neighbor_search_grids(const SculptSession &ss,
const CCGKey &key,
const Span<CCGElem *> elems,
const Span<float3> positions,
const BitGroupVector<> &grid_hidden,
const float3 &location,
const float max_distance_sq,
@@ -5990,21 +5984,18 @@ static void fake_neighbor_search_grids(const SculptSession &ss,
NearestVertData &nvtd)
{
for (const int grid : node.grids()) {
const int verts_start = grid * key.grid_area;
CCGElem *elem = elems[grid];
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int offset) {
const int vert = verts_start + offset;
const int vert = grid_range[offset];
if (ss.fake_neighbors.fake_neighbor_index[vert] != FAKE_NEIGHBOR_NONE) {
return;
}
if (islands::vert_id_get(ss, vert) == island_id) {
return;
}
const float distance_sq = math::distance_squared(CCG_elem_offset_co(key, elem, offset),
location);
const float distance_sq = math::distance_squared(positions[vert], location);
if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
nvtd.vert = vert;
BLI_assert(nvtd.vert < key.grid_area * elems.size());
nvtd.distance_sq = distance_sq;
}
});
@@ -6101,15 +6092,14 @@ static void fake_neighbor_search(const Depsgraph &depsgraph,
case bke::pbvh::Type::Grids: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
for (const int vert : IndexRange(elems.size() * key.grid_area)) {
for (const int vert : positions.index_range()) {
if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
continue;
}
const int island_id = islands::vert_id_get(ss, vert);
const SubdivCCGCoord coord = SubdivCCGCoord::from_index(key, vert);
const float3 &location = CCG_grid_elem_co(key, elems[coord.grid_index], coord.x, coord.y);
const float3 &location = positions[vert];
IndexMaskMemory memory;
const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
pbvh, memory, [&](const bke::pbvh::Node &node) {
@@ -6127,7 +6117,7 @@ static void fake_neighbor_search(const Depsgraph &depsgraph,
nodes_in_sphere.slice(range).foreach_index([&](const int i) {
fake_neighbor_search_grids(ss,
key,
elems,
positions,
grid_hidden,
location,
max_distance_sq,
@@ -6402,9 +6392,8 @@ static SculptTopologyIslandCache calc_topology_islands_grids(const Object &objec
const SculptSession &ss = *object.sculpt;
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int verts_num = subdiv_ccg.grids.size() * key.grid_area;
AtomicDisjointSet disjoint_set(verts_num);
threading::parallel_for(subdiv_ccg.grids.index_range(), 512, [&](const IndexRange range) {
AtomicDisjointSet disjoint_set(subdiv_ccg.positions.size());
threading::parallel_for(IndexRange(subdiv_ccg.grids_num), 512, [&](const IndexRange range) {
for (const int grid : range) {
SubdivCCGNeighbors neighbors;
for (const short y : IndexRange(key.grid_size)) {
@@ -6420,7 +6409,7 @@ static SculptTopologyIslandCache calc_topology_islands_grids(const Object &objec
}
});
return vert_disjoint_set_to_islands(disjoint_set, verts_num);
return vert_disjoint_set_to_islands(disjoint_set, subdiv_ccg.positions.size());
}
static SculptTopologyIslandCache calc_topology_islands_bmesh(const Object &object)
@@ -6506,22 +6495,6 @@ void SCULPT_cube_tip_init(const Sculpt & /*sd*/,
namespace blender::ed::sculpt_paint {
void gather_grids_positions(const CCGKey &key,
const Span<CCGElem *> elems,
const Span<int> grids,
const MutableSpan<float3> positions)
{
BLI_assert(grids.size() * key.grid_area == positions.size());
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
positions[start + offset] = CCG_elem_offset_co(key, elem, offset);
}
}
}
void gather_bmesh_positions(const Set<BMVert *, 0> &verts, const MutableSpan<float3> positions)
{
BLI_assert(verts.size() == positions.size());
@@ -6537,17 +6510,7 @@ void gather_grids_normals(const SubdivCCG &subdiv_ccg,
const Span<int> grids,
const MutableSpan<float3> normals)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
BLI_assert(grids.size() * key.grid_area == normals.size());
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
normals[start + offset] = CCG_elem_offset_no(key, elem, offset);
}
}
gather_data_grids(subdiv_ccg, subdiv_ccg.normals.as_span(), grids, normals);
}
void gather_bmesh_normals(const Set<BMVert *, 0> &verts, const MutableSpan<float3> normals)
@@ -6579,9 +6542,9 @@ void gather_data_grids(const SubdivCCG &subdiv_ccg,
BLI_assert(grids.size() * key.grid_area == node_data.size());
for (const int i : grids.index_range()) {
const int node_start = i * key.grid_area;
const int grids_start = grids[i] * key.grid_area;
node_data.slice(node_start, key.grid_area).copy_from(src.slice(grids_start, key.grid_area));
const IndexRange grids_range = bke::ccg::grid_range(key, grids[i]);
const IndexRange node_range = bke::ccg::grid_range(key, i);
node_data.slice(node_range).copy_from(src.slice(grids_range));
}
}
@@ -6619,9 +6582,9 @@ void scatter_data_grids(const SubdivCCG &subdiv_ccg,
BLI_assert(grids.size() * key.grid_area == node_data.size());
for (const int i : grids.index_range()) {
const int node_start = i * key.grid_area;
const int grids_start = grids[i] * key.grid_area;
dst.slice(grids_start, key.grid_area).copy_from(node_data.slice(node_start, key.grid_area));
const IndexRange grids_range = bke::ccg::grid_range(key, grids[i]);
const IndexRange node_range = bke::ccg::grid_range(key, i);
dst.slice(grids_range).copy_from(node_data.slice(node_range));
}
}
@@ -6778,15 +6741,15 @@ void fill_factor_from_hide_and_mask(const SubdivCCG &subdiv_ccg,
const MutableSpan<float> r_factors)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
BLI_assert(grids.size() * key.grid_area == r_factors.size());
if (key.has_mask) {
if (!subdiv_ccg.masks.is_empty()) {
const Span<float> masks = subdiv_ccg.masks;
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
r_factors[start + offset] = 1.0f - CCG_elem_offset_mask(key, elem, offset);
const Span src = masks.slice(bke::ccg::grid_range(key, grids[i]));
MutableSpan dst = r_factors.slice(bke::ccg::grid_range(key, i));
for (const int offset : dst.index_range()) {
dst[offset] = 1.0f - src[offset];
}
}
}
@@ -6838,15 +6801,15 @@ void calc_front_face(const float3 &view_normal,
const MutableSpan<float> factors)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> normals = subdiv_ccg.normals;
BLI_assert(grids.size() * key.grid_area == factors.size());
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
const float dot = math::dot(view_normal, CCG_elem_offset_no(key, elem, offset));
factors[start + offset] *= std::max(dot, 0.0f);
const Span<float3> grid_normals = normals.slice(bke::ccg::grid_range(key, grids[i]));
MutableSpan<float> grid_factors = factors.slice(bke::ccg::grid_range(key, i));
for (const int offset : grid_factors.index_range()) {
const float dot = math::dot(view_normal, grid_normals[offset]);
grid_factors[offset] *= std::max(dot, 0.0f);
}
}
}
@@ -7217,14 +7180,14 @@ void apply_translations(const Span<float3> translations,
SubdivCCG &subdiv_ccg)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
MutableSpan<float3> positions = subdiv_ccg.positions;
BLI_assert(grids.size() * key.grid_area == translations.size());
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
CCG_elem_offset_co(key, elem, offset) += translations[start + offset];
const Span<float3> grid_translations = translations.slice(bke::ccg::grid_range(key, i));
MutableSpan<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grids[i]));
for (const int offset : grid_positions.index_range()) {
grid_positions[offset] += grid_translations[offset];
}
}
}

View File

@@ -434,14 +434,14 @@ static void calc_blurred_cavity_grids(const Object &object,
const SubdivCCGCoord vert)
{
struct CavityBlurVert {
SubdivCCGCoord vertex;
int index;
int vert;
int depth;
};
const SculptSession &ss = *object.sculpt;
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const Span<float3> normals = subdiv_ccg.normals;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
AccumulatedVert all_verts;
@@ -454,23 +454,21 @@ static void calc_blurred_cavity_grids(const Object &object,
std::queue<CavityBlurVert> queue;
Set<int, 64> visited_verts;
const CavityBlurVert initial{vert, vert.to_index(key), 0};
visited_verts.add_new(initial.index);
const CavityBlurVert initial{vert.to_index(key), 0};
visited_verts.add_new(initial.vert);
queue.push(initial);
const float3 starting_position = CCG_grid_elem_co(key, grids[vert.grid_index], vert.x, vert.y);
const float3 starting_position = positions[vert.to_index(key)];
SubdivCCGNeighbors neighbors;
while (!queue.empty()) {
const CavityBlurVert blurvert = queue.front();
queue.pop();
const SubdivCCGCoord current_vert = blurvert.vertex;
const int current_vert = blurvert.vert;
const float3 blur_vert_position = CCG_grid_elem_co(
key, grids[current_vert.grid_index], current_vert.x, current_vert.y);
const float3 blur_vert_normal = CCG_grid_elem_no(
key, grids[current_vert.grid_index], current_vert.x, current_vert.y);
const float3 blur_vert_position = positions[current_vert];
const float3 blur_vert_normal = normals[current_vert];
const float dist_to_start = math::distance(blur_vert_position, starting_position);
@@ -490,7 +488,8 @@ static void calc_blurred_cavity_grids(const Object &object,
continue;
}
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, current_vert, false, neighbors);
BKE_subdiv_ccg_neighbor_coords_get(
subdiv_ccg, SubdivCCGCoord::from_index(key, current_vert), false, neighbors);
for (const SubdivCCGCoord neighbor : neighbors.coords) {
const int neighbor_idx = neighbor.to_index(key);
if (visited_verts.contains(neighbor_idx)) {
@@ -498,14 +497,14 @@ static void calc_blurred_cavity_grids(const Object &object,
}
visited_verts.add_new(neighbor_idx);
queue.push({neighbor, neighbor_idx, blurvert.depth + 1});
queue.push({neighbor_idx, blurvert.depth + 1});
}
}
BLI_assert(all_verts.count != verts_in_range.count);
if (all_verts.count == 0) {
all_verts.position = CCG_grid_elem_co(key, grids[vert.grid_index], vert.x, vert.y);
all_verts.position = positions[vert.to_index(key)];
}
else {
all_verts.position /= float(all_verts.count);
@@ -513,7 +512,7 @@ static void calc_blurred_cavity_grids(const Object &object,
}
if (verts_in_range.count == 0) {
verts_in_range.position = CCG_grid_elem_co(key, grids[vert.grid_index], vert.x, vert.y);
verts_in_range.position = positions[vert.to_index(key)];
}
else {
verts_in_range.position /= float(verts_in_range.count);
@@ -521,7 +520,7 @@ static void calc_blurred_cavity_grids(const Object &object,
verts_in_range.normal = math::normalize(verts_in_range.normal);
if (math::dot(verts_in_range.normal, verts_in_range.normal) == 0.0f) {
verts_in_range.normal = CCG_grid_elem_no(key, grids[vert.grid_index], vert.x, vert.y);
verts_in_range.normal = normals[vert.to_index(key)];
}
const float3 vec = all_verts.position - verts_in_range.position;
@@ -948,29 +947,24 @@ static void fill_topology_automasking_factors_grids(const Sculpt &sd,
const float radius = ss.cache ? ss.cache->radius : std::numeric_limits<float>::max();
const SubdivCCGCoord active_vert = std::get<SubdivCCGCoord>(ss.active_vert());
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int grid_verts_num = subdiv_ccg.grids.size() * key.grid_area;
flood_fill::FillDataGrids flood = flood_fill::FillDataGrids(grid_verts_num);
flood_fill::FillDataGrids flood = flood_fill::FillDataGrids(positions.size());
flood.add_initial_with_symmetry(ob, *bke::object::pbvh_get(ob), subdiv_ccg, active_vert, radius);
const bool use_radius = ss.cache && is_constrained_by_radius(brush);
const ePaintSymmetryFlags symm = SCULPT_mesh_symmetry_xyz_get(ob);
float3 location = CCG_grid_elem_co(
key, grids[active_vert.grid_index], active_vert.x, active_vert.y);
float3 location = positions[active_vert.to_index(key)];
flood.execute(
ob, subdiv_ccg, [&](SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool /*is_duplicate*/) {
*(float *)SCULPT_vertex_attr_get(key, to_v, ss.attrs.automasking_factor) = 1.0f;
*(float *)SCULPT_vertex_attr_get(key, from_v, ss.attrs.automasking_factor) = 1.0f;
return (use_radius || SCULPT_is_vertex_inside_brush_radius_symm(
CCG_grid_elem_co(key, grids[to_v.grid_index], to_v.x, to_v.y),
location,
radius,
symm));
positions[to_v.to_index(key)], location, radius, symm));
});
}
@@ -1119,15 +1113,14 @@ static void init_boundary_masking_grids(Object &object,
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
Mesh &mesh = *static_cast<Mesh *>(object.data);
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const OffsetIndices faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts();
const int num_grids = key.grid_area * grids.size();
Array<int> edge_distance(num_grids, EDGE_DISTANCE_INF);
for (const int i : IndexRange(num_grids)) {
Array<int> edge_distance(positions.size(), EDGE_DISTANCE_INF);
for (const int i : positions.index_range()) {
const SubdivCCGCoord coord = SubdivCCGCoord::from_index(key, i);
switch (mode) {
case BoundaryAutomaskMode::Edges:
@@ -1149,7 +1142,7 @@ static void init_boundary_masking_grids(Object &object,
SubdivCCGNeighbors neighbors;
for (const int propagation_it : IndexRange(propagation_steps)) {
for (const int i : IndexRange(num_grids)) {
for (const int i : positions.index_range()) {
if (edge_distance[i] != EDGE_DISTANCE_INF) {
continue;
}
@@ -1166,7 +1159,7 @@ static void init_boundary_masking_grids(Object &object,
}
}
for (const int i : IndexRange(num_grids)) {
for (const int i : positions.index_range()) {
if (edge_distance[i] == EDGE_DISTANCE_INF) {
continue;
}

View File

@@ -204,19 +204,17 @@ static std::optional<SubdivCCGCoord> get_closest_boundary_vert_grids(
return initial_vert;
}
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int num_grids = key.grid_area * grids.size();
flood_fill::FillDataGrids flood_fill(num_grids);
flood_fill::FillDataGrids flood_fill(positions.size());
flood_fill.add_initial(initial_vert);
const float3 initial_vert_position = CCG_grid_elem_co(
key, grids[initial_vert.grid_index], initial_vert.x, initial_vert.y);
const float3 initial_vert_position = positions[initial_vert.to_index(key)];
const float radius_sq = radius * radius;
int boundary_initial_vert_steps = std::numeric_limits<int>::max();
Array<int> floodfill_steps(num_grids, 0);
Array<int> floodfill_steps(positions.size(), 0);
std::optional<SubdivCCGCoord> boundary_initial_vert;
flood_fill.execute(
@@ -242,8 +240,8 @@ static std::optional<SubdivCCGCoord> get_closest_boundary_vert_grids(
}
}
const float len_sq = math::distance_squared(
initial_vert_position, CCG_grid_elem_co(key, grids[to_v.grid_index], to_v.x, to_v.y));
const float len_sq = math::distance_squared(initial_vert_position,
positions[to_v.to_index(key)]);
return len_sq < radius_sq;
});
@@ -361,10 +359,9 @@ static void indices_init_grids(Object &object,
const SubdivCCGCoord initial_vert,
SculptBoundary &boundary)
{
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int num_grids = key.grid_area * grids.size();
flood_fill::FillDataGrids flood_fill(num_grids);
flood_fill::FillDataGrids flood_fill(positions.size());
const int initial_boundary_index = initial_vert.to_index(key);
Set<int, BOUNDARY_INDICES_BLOCK_SIZE> included_verts;
@@ -378,12 +375,8 @@ static void indices_init_grids(Object &object,
const int from_v_i = from_v.to_index(key);
const int to_v_i = to_v.to_index(key);
const float3 from_v_co = CCG_elem_offset_co(
key,
grids[from_v.grid_index],
CCG_grid_xy_to_index(key.grid_size, from_v.x, from_v.y));
const float3 to_v_co = CCG_elem_offset_co(
key, grids[to_v.grid_index], CCG_grid_xy_to_index(key.grid_size, to_v.x, to_v.y));
const float3 &from_v_co = positions[from_v_i];
const float3 &to_v_co = positions[to_v_i];
if (!boundary::vert_is_boundary(subdiv_ccg, corner_verts, faces, boundary_verts, to_v)) {
return false;
@@ -534,13 +527,12 @@ static void edit_data_init_grids(const SubdivCCG &subdiv_ccg,
const float radius,
SculptBoundary &boundary)
{
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int num_grids = key.grid_area * grids.size();
boundary.edit_info.original_vertex_i = Array<int>(num_grids, BOUNDARY_VERTEX_NONE);
boundary.edit_info.propagation_steps_num = Array<int>(num_grids, BOUNDARY_STEPS_NONE);
boundary.edit_info.strength_factor = Array<float>(num_grids, 0.0f);
boundary.edit_info.original_vertex_i = Array<int>(positions.size(), BOUNDARY_VERTEX_NONE);
boundary.edit_info.propagation_steps_num = Array<int>(positions.size(), BOUNDARY_STEPS_NONE);
boundary.edit_info.strength_factor = Array<float>(positions.size(), 0.0f);
std::queue<SubdivCCGCoord> current_iteration;
@@ -639,11 +631,8 @@ static void edit_data_init_grids(const SubdivCCG &subdiv_ccg,
/* Check the distance using the vertex that was propagated from the initial vertex that
* was used to initialize the boundary. */
if (boundary.edit_info.original_vertex_i[from_v_i] == initial_vert_i) {
boundary.pivot_position = CCG_elem_offset_co(
key, grids[neighbor.grid_index], index_in_grid);
accum_distance += math::distance(
CCG_grid_elem_co(key, grids[from_v.grid_index], from_v.x, from_v.y),
boundary.pivot_position);
boundary.pivot_position = positions[neighbor_idx];
accum_distance += math::distance(positions[from_v_i], boundary.pivot_position);
}
}
}
@@ -798,8 +787,8 @@ static void bend_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &bo
const int num_elements = boundary.edit_info.strength_factor.size();
const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const Span<float3> normals = subdiv_ccg.normals;
boundary.bend.pivot_rotation_axis = Array<float3>(num_elements, float3(0));
boundary.bend.pivot_positions = Array<float3>(num_elements, float3(0));
@@ -809,17 +798,12 @@ static void bend_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &bo
continue;
}
const SubdivCCGCoord vert = SubdivCCGCoord::from_index(key, i);
const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
const SubdivCCGCoord orig_vert = SubdivCCGCoord::from_index(key, orig_vert_i);
const float3 normal = CCG_grid_elem_no(key, grids[vert.grid_index], vert.x, vert.y);
const float3 dir = CCG_grid_elem_co(
key, grids[orig_vert.grid_index], orig_vert.x, orig_vert.y) -
CCG_grid_elem_co(key, grids[vert.grid_index], vert.x, vert.y);
const float3 normal = normals[i];
const float3 dir = positions[orig_vert_i] - positions[i];
boundary.bend.pivot_rotation_axis[orig_vert_i] = math::normalize(math::cross(dir, normal));
boundary.bend.pivot_positions[orig_vert_i] = CCG_grid_elem_co(
key, grids[vert.grid_index], vert.x, vert.y);
boundary.bend.pivot_positions[orig_vert_i] = positions[i];
}
for (const int i : IndexRange(num_elements)) {
@@ -906,8 +890,7 @@ static void slide_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &b
boundary.edit_info.strength_factor.size());
const int num_elements = boundary.edit_info.strength_factor.size();
const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
boundary.slide.directions = Array<float3>(num_elements, float3(0));
@@ -915,13 +898,10 @@ static void slide_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &b
if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
continue;
}
const SubdivCCGCoord vert = SubdivCCGCoord::from_index(key, i);
const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
const SubdivCCGCoord orig_vert = SubdivCCGCoord::from_index(key, orig_vert_i);
boundary.slide.directions[orig_vert_i] = math::normalize(
CCG_grid_elem_co(key, grids[orig_vert.grid_index], orig_vert.x, orig_vert.y) -
CCG_grid_elem_co(key, grids[vert.grid_index], vert.x, vert.y));
boundary.slide.directions[orig_vert_i] = math::normalize(positions[orig_vert_i] -
positions[i]);
}
for (const int i : IndexRange(num_elements)) {
@@ -983,14 +963,9 @@ static void twist_data_init_mesh(const Span<float3> vert_positions, SculptBounda
static void twist_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &boundary)
{
const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> vert_positions = subdiv_ccg.positions;
Array<float3> positions(boundary.verts.size());
for (const int i : positions.index_range()) {
const SubdivCCGCoord vert = SubdivCCGCoord::from_index(key, boundary.verts[i]);
positions[i] = CCG_grid_elem_co(key, grids[vert.grid_index], vert.x, vert.y);
}
array_utils::gather(vert_positions, boundary.verts.as_span(), positions.as_mutable_span());
populate_twist_data(positions, boundary);
}
@@ -2571,7 +2546,7 @@ BLI_NOINLINE static void calc_average_position(const SubdivCCG &subdiv_ccg,
const MutableSpan<float3> average_positions)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
BLI_assert(neighbors.size() == propagation_steps.size());
BLI_assert(neighbors.size() == factors.size());
@@ -2582,8 +2557,7 @@ BLI_NOINLINE static void calc_average_position(const SubdivCCG &subdiv_ccg,
int valid_neighbors = 0;
for (const SubdivCCGCoord neighbor : neighbors[i]) {
if (propagation_steps[i] == vert_propagation_steps[neighbor.to_index(key)]) {
average_positions[i] += CCG_grid_elem_co(
key, grids[neighbor.grid_index], neighbor.x, neighbor.y);
average_positions[i] += positions[neighbor.to_index(key)];
valid_neighbors++;
}
}
@@ -3027,18 +3001,14 @@ static void init_falloff_grids(const SubdivCCG &subdiv_ccg,
boundary.edit_info.strength_factor.size());
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
Span<CCGElem *> grids = subdiv_ccg.grids;
BKE_curvemapping_init(brush.curve);
for (const int i : grids.index_range()) {
const int start = i * key.grid_area;
for (const int offset : IndexRange(key.grid_area)) {
const int index = start + offset;
for (const int grid : IndexRange(subdiv_ccg.grids_num)) {
for (const int index : bke::ccg::grid_range(key, grid)) {
if (boundary.edit_info.propagation_steps_num[index] != BOUNDARY_STEPS_NONE) {
const float mask_factor = key.has_mask ?
1.0f - CCG_elem_offset_mask(key, grids[i], offset) :
1.0f;
const float mask_factor = subdiv_ccg.masks.is_empty() ? 1.0f - subdiv_ccg.masks[index] :
1.0f;
boundary.edit_info.strength_factor[index] =
mask_factor * BKE_brush_curve_strength(&brush,
boundary.edit_info.propagation_steps_num[index],
@@ -3189,7 +3159,7 @@ static void init_boundary_grids(Object &object,
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
ActiveVert initial_vert_ref = ss.active_vert();
if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
@@ -3202,9 +3172,7 @@ static void init_boundary_grids(Object &object,
}
else {
const SubdivCCGCoord active_vert = std::get<SubdivCCGCoord>(initial_vert_ref);
float3 location = symmetry_flip(
CCG_grid_elem_co(key, grids[active_vert.grid_index], active_vert.x, active_vert.y),
symm_area);
float3 location = symmetry_flip(positions[active_vert.to_index(key)], symm_area);
initial_vert = nearest_vert_calc_grids(
pbvh, subdiv_ccg, location, ss.cache->radius_squared, false);
}
@@ -3553,7 +3521,7 @@ std::unique_ptr<SculptBoundary> data_init_grids(Object &object,
const OffsetIndices faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts();
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const std::optional<SubdivCCGCoord> boundary_initial_vert = get_closest_boundary_vert_grids(
@@ -3577,8 +3545,7 @@ std::unique_ptr<SculptBoundary> data_init_grids(Object &object,
SubdivCCGCoord boundary_vert = *boundary_initial_vert;
const int boundary_initial_vert_index = boundary_vert.to_index(key);
boundary->initial_vert_i = boundary_initial_vert_index;
boundary->initial_vert_position = CCG_grid_elem_co(
key, grids[boundary_vert.grid_index], boundary_vert.x, boundary_vert.y);
boundary->initial_vert_position = positions[boundary_initial_vert_index];
indices_init_grids(
object, faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, boundary_vert, *boundary);

View File

@@ -1443,7 +1443,8 @@ void do_simulation_step(const Depsgraph &depsgraph,
});
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> cloth_positions = cloth_sim.pos;
MutableSpan<float3> positions = subdiv_ccg.positions;
threading::parallel_for(active_nodes.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
active_nodes.slice(range).foreach_index([&](const int i) {
@@ -1459,14 +1460,9 @@ void do_simulation_step(const Depsgraph &depsgraph,
const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
for (const int i : grids.index_range()) {
const int grid = grids[i];
const int start = grid * key.grid_area;
CCGElem *elem = elems[grid];
for (const int offset : IndexRange(key.grid_area)) {
const int grid_vert_index = start + offset;
CCG_elem_offset_co(key, elem, offset) = cloth_sim.pos[grid_vert_index];
}
for (const int grid : grids) {
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
positions.slice(grid_range).copy_from(cloth_positions.slice(grid_range));
}
cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =

View File

@@ -394,11 +394,10 @@ static BitVector<> enabled_state_to_bitmap(const Depsgraph &depsgraph,
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
for (const int grid : subdiv_ccg.grids.index_range()) {
for (const int grid : IndexRange(subdiv_ccg.grids_num)) {
const int start = grid * key.grid_area;
CCGElem *elem = elems[grid];
const int face_set = face_sets[grid_to_face_map[grid]];
BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int offset) {
const int vert = start + offset;
@@ -409,8 +408,8 @@ static BitVector<> enabled_state_to_bitmap(const Depsgraph &depsgraph,
enabled_verts[vert].set(expand_cache.snap_enabled_face_sets->contains(face_set));
return;
}
enabled_verts[vert].set(vert_falloff_is_enabled(
ss, expand_cache, CCG_elem_offset_co(key, elem, offset), vert));
enabled_verts[vert].set(
vert_falloff_is_enabled(ss, expand_cache, positions[vert], vert));
});
}
break;
@@ -593,10 +592,8 @@ static Vector<int> calc_symmetry_vert_indices(const Depsgraph &depsgraph,
case bke::pbvh::Type::Grids: {
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const SubdivCCGCoord original_coord = SubdivCCGCoord::from_index(key, original_vert);
const float3 location = CCG_grid_elem_co(
key, elems[original_coord.grid_index], original_coord.x, original_coord.y);
const Span<float3> positions = subdiv_ccg.positions;
const float3 location = positions[original_vert];
for (char symm_it = 1; symm_it <= symm; symm_it++) {
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
continue;
@@ -812,13 +809,11 @@ static Array<float> normals_falloff_create(const Depsgraph &depsgraph,
case bke::pbvh::Type::Grids: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const SubdivCCGCoord orig_coord = SubdivCCGCoord::from_index(key, v.i);
const float3 orig_normal = CCG_grid_elem_no(
key, elems[orig_coord.grid_index], orig_coord.x, orig_coord.y);
const Span<float3> normals = subdiv_ccg.normals;
const float3 orig_normal = normals[v.i];
flood_fill::FillDataGrids flood(totvert);
flood.add_initial_with_symmetry(ob, pbvh, subdiv_ccg, orig_coord, FLT_MAX);
flood.add_initial_with_symmetry(
ob, pbvh, subdiv_ccg, SubdivCCGCoord::from_index(key, v.i), FLT_MAX);
flood.execute(
ob,
subdiv_ccg,
@@ -830,9 +825,8 @@ static Array<float> normals_falloff_create(const Depsgraph &depsgraph,
dists[to_vert] = dists[from_vert];
}
else {
const float3 &from_normal = CCG_grid_elem_no(
key, elems[from.grid_index], from.x, from.y);
const float3 &to_normal = CCG_grid_elem_no(key, elems[to.grid_index], to.x, to.y);
const float3 &from_normal = normals[from_vert];
const float3 &to_normal = normals[to_vert];
const float from_edge_factor = edge_factors[from_vert];
const float dist = math::dot(orig_normal, to_normal) *
powf(from_edge_factor, edge_sensitivity);
@@ -908,28 +902,20 @@ static Array<float> spherical_falloff_create(const Depsgraph &depsgraph,
}
case bke::pbvh::Type::Grids: {
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
Array<float3> locations(symm_verts.size());
for (const int i : symm_verts.index_range()) {
const SubdivCCGCoord coord = SubdivCCGCoord::from_index(key, symm_verts[i]);
locations[i] = CCG_grid_elem_co(key, elems[coord.grid_index], coord.x, coord.y);
locations[i] = positions[symm_verts[i]];
}
threading::parallel_for(elems.index_range(), 1024, [&](const IndexRange range) {
for (const int grid : range) {
const int start = grid * key.grid_area;
CCGElem *elem = elems[grid];
for (const int offset : IndexRange(key.grid_area)) {
const int vert = start + offset;
float dist = std::numeric_limits<float>::max();
for (const float3 &location : locations) {
dist = std::min(dist,
math::distance(CCG_elem_offset_co(key, elem, offset), location));
}
dists[vert] = dist;
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (const int vert : range) {
float dist = std::numeric_limits<float>::max();
for (const float3 &location : locations) {
dist = std::min(dist, math::distance(positions[vert], location));
}
dists[vert] = dist;
}
});
break;
@@ -1517,19 +1503,9 @@ static void write_mask_data(Object &object, const Span<float> mask)
break;
}
case bke::pbvh::Type::Grids: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
int index = 0;
for (const int grid : grids.index_range()) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
CCG_elem_offset_mask(key, elem, i) = mask[index];
index++;
}
}
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
subdiv_ccg.masks.as_mutable_span().copy_from(mask);
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_update_mask(nodes[i]); });
break;
}
@@ -1620,17 +1596,13 @@ static void update_mask_grids(const SculptSession &ss,
{
const Cache &expand_cache = *ss.expand_cache;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
MutableSpan<float> masks = subdiv_ccg.masks;
bool any_changed = false;
const Span<int> grids = node.grids();
for (const int i : grids.index_range()) {
const int grid = grids[i];
const int start = grid * key.grid_area;
CCGElem *elem = elems[grid];
for (const int offset : IndexRange(key.grid_area)) {
const int vert = start + offset;
const float initial_mask = CCG_elem_offset_mask(key, elem, offset);
for (const int grid : node.grids()) {
for (const int vert : bke::ccg::grid_range(key, grid)) {
const float initial_mask = masks[vert];
if (expand_cache.check_islands && !is_vert_in_active_component(ss, expand_cache, vert)) {
continue;
@@ -1639,8 +1611,7 @@ static void update_mask_grids(const SculptSession &ss,
float new_mask;
if (enabled_verts[vert]) {
new_mask = gradient_value_get(
ss, expand_cache, CCG_elem_offset_co(key, elem, offset), vert);
new_mask = gradient_value_get(ss, expand_cache, positions[vert], vert);
}
else {
new_mask = 0.0f;
@@ -1659,7 +1630,7 @@ static void update_mask_grids(const SculptSession &ss,
continue;
}
CCG_elem_offset_mask(key, elem, offset) = clamp_f(new_mask, 0.0f, 1.0f);
masks[vert] = clamp_f(new_mask, 0.0f, 1.0f);
any_changed = true;
}
}
@@ -2578,18 +2549,12 @@ static bool any_nonzero_mask(const Object &object)
}
case bke::pbvh::Type::Grids: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (!key.has_mask) {
const Span<float> mask = subdiv_ccg.masks;
if (mask.is_empty()) {
return false;
}
return std::any_of(subdiv_ccg.grids.begin(), subdiv_ccg.grids.end(), [&](CCGElem *elem) {
for (const int i : IndexRange(key.grid_area)) {
if (CCG_elem_offset_mask(key, elem, i) > 0.0f) {
return true;
}
}
return false;
});
return std::any_of(
mask.begin(), mask.end(), [&](const float value) { return value > 0.0f; });
}
case bke::pbvh::Type::BMesh: {
BMesh &bm = *ss.bm;

View File

@@ -275,13 +275,12 @@ BLI_NOINLINE static void copy_old_hidden_mask_grids(const SubdivCCG &subdiv_ccg,
return;
}
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float> masks = subdiv_ccg.masks;
for (const int i : grids.index_range()) {
const int node_verts_start = i * key.grid_area;
CCGElem *elem = elems[grids[i]];
bits::foreach_1_index(grid_hidden[grids[i]], [&](const int offset) {
new_mask[node_verts_start + offset] = CCG_elem_offset_mask(key, elem, offset);
});
const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grids[i]));
MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
bits::foreach_1_index(grid_hidden[grids[i]],
[&](const int offset) { grid_dst[offset] = grid_masks[offset]; });
}
}
@@ -296,15 +295,16 @@ static void apply_new_mask_grids(const Depsgraph &depsgraph,
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
MutableSpan<float> masks = subdiv_ccg.masks;
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
const Span<int> grids = nodes[i].grids();
const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
if (mask_equals_array_grids(subdiv_ccg.grids, key, grids, new_node_mask)) {
if (mask_equals_array_grids(masks, key, grids, new_node_mask)) {
return;
}
undo::push_node(depsgraph, object, &nodes[i], undo::Type::Mask);
scatter_mask_grids(new_node_mask, subdiv_ccg, grids);
scatter_data_grids(subdiv_ccg, new_node_mask, grids, masks);
BKE_pbvh_node_mark_update_mask(nodes[i]);
});
@@ -317,7 +317,7 @@ static void smooth_mask_grids(const SubdivCCG &subdiv_ccg,
MutableSpan<float> new_mask)
{
const Span<int> grids = node.grids();
average_neighbor_mask_grids(subdiv_ccg, node.grids(), new_mask);
smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
}
@@ -333,9 +333,9 @@ static void sharpen_mask_grids(const SubdivCCG &subdiv_ccg,
tls.node_mask.resize(grid_verts_num);
const MutableSpan<float> node_mask = tls.node_mask;
gather_mask_grids(subdiv_ccg, grids, node_mask);
gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
average_neighbor_mask_grids(subdiv_ccg, grids, new_mask);
smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
sharpen_masks(node_mask, new_mask);
@@ -347,28 +347,26 @@ static void grow_mask_grids(const SubdivCCG &subdiv_ccg,
MutableSpan<float> new_mask)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float> masks = subdiv_ccg.masks;
const Span<int> grids = node.grids();
for (const int i : grids.index_range()) {
const int grid = grids[i];
CCGElem *elem = elems[grid];
const int node_verts_start = i * key.grid_area;
const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
for (const short y : IndexRange(key.grid_size)) {
for (const short x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert_index = node_verts_start + offset;
SubdivCCGNeighbors neighbors;
SubdivCCGCoord coord{grid, x, y};
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
new_mask[node_vert_index] = CCG_elem_offset_mask(key, elem, offset);
grid_dst[offset] = grid_masks[offset];
for (const SubdivCCGCoord neighbor : neighbors.coords) {
new_mask[node_vert_index] = std::max(
CCG_grid_elem_mask(key, elem, neighbor.x, neighbor.y), new_mask[node_vert_index]);
grid_dst[offset] = std::max(masks[neighbor.to_index(key)], grid_dst[offset]);
}
}
}
@@ -382,28 +380,26 @@ static void shrink_mask_grids(const SubdivCCG &subdiv_ccg,
MutableSpan<float> new_mask)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float> masks = subdiv_ccg.masks;
const Span<int> grids = node.grids();
for (const int i : grids.index_range()) {
const int grid = grids[i];
CCGElem *elem = elems[grid];
const int node_verts_start = i * key.grid_area;
const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
for (const short y : IndexRange(key.grid_size)) {
for (const short x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert_index = node_verts_start + offset;
SubdivCCGNeighbors neighbors;
SubdivCCGCoord coord{grid, x, y};
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
new_mask[node_vert_index] = CCG_elem_offset_mask(key, elem, offset);
grid_dst[offset] = grid_masks[offset];
for (const SubdivCCGCoord neighbor : neighbors.coords) {
new_mask[node_vert_index] = std::min(
CCG_grid_elem_mask(key, elem, neighbor.x, neighbor.y), new_mask[node_vert_index]);
grid_dst[offset] = std::min(masks[neighbor.to_index(key)], grid_dst[offset]);
}
}
}
@@ -426,7 +422,7 @@ static void increase_contrast_mask_grids(const Depsgraph &depsgraph,
tls.node_mask.resize(grid_verts_num);
const MutableSpan<float> node_mask = tls.node_mask;
gather_mask_grids(subdiv_ccg, grids, node_mask);
gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
tls.new_mask.resize(grid_verts_num);
const MutableSpan<float> new_mask = tls.new_mask;
@@ -439,7 +435,7 @@ static void increase_contrast_mask_grids(const Depsgraph &depsgraph,
}
undo::push_node(depsgraph, object, &node, undo::Type::Mask);
scatter_mask_grids(new_mask.as_span(), subdiv_ccg, grids);
scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
BKE_pbvh_node_mark_update_mask(node);
}
@@ -457,7 +453,7 @@ static void decrease_contrast_mask_grids(const Depsgraph &depsgraph,
tls.node_mask.resize(grid_verts_num);
const MutableSpan<float> node_mask = tls.node_mask;
gather_mask_grids(subdiv_ccg, grids, node_mask);
gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
tls.new_mask.resize(grid_verts_num);
const MutableSpan<float> new_mask = tls.new_mask;
@@ -470,7 +466,7 @@ static void decrease_contrast_mask_grids(const Depsgraph &depsgraph,
}
undo::push_node(depsgraph, object, &node, undo::Type::Mask);
scatter_mask_grids(new_mask.as_span(), subdiv_ccg, grids);
scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
BKE_pbvh_node_mark_update_mask(node);
}

View File

@@ -1097,7 +1097,6 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
grids,
false,
factors,
positions,
tls.vert_neighbors,
translations);
@@ -1274,7 +1273,6 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
grids,
relax_face_sets,
factors,
positions,
tls.vert_neighbors,
translations);
@@ -1464,7 +1462,8 @@ static void calc_surface_smooth_filter(const Depsgraph &depsgraph,
tls.average_positions.resize(positions.size());
const MutableSpan<float3> average_positions = tls.average_positions;
smooth::neighbor_position_average_grids(subdiv_ccg, grids, average_positions);
smooth::average_data_grids(
subdiv_ccg, subdiv_ccg.positions.as_span(), grids, average_positions);
tls.laplacian_disp.resize(positions.size());
const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;
@@ -1726,7 +1725,7 @@ static void calc_sharpen_filter(const Depsgraph &depsgraph,
case bke::pbvh::Type::Grids: {
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
MutableSpan<float3> vert_positions = subdiv_ccg.positions;
threading::EnumerableThreadSpecific<LocalData> all_tls;
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
@@ -1755,7 +1754,8 @@ static void calc_sharpen_filter(const Depsgraph &depsgraph,
tls.smooth_positions.resize(positions.size());
const MutableSpan<float3> smooth_positions = tls.smooth_positions;
smooth::neighbor_position_average_grids(subdiv_ccg, grids, smooth_positions);
smooth::average_data_grids(
subdiv_ccg, subdiv_ccg.positions.as_span(), grids, smooth_positions);
const Span<float> sharpen_factors = gather_data_grids(
subdiv_ccg, ss.filter_cache->sharpen_factor.as_span(), grids, tls.sharpen_factors);
@@ -1777,9 +1777,7 @@ static void calc_sharpen_filter(const Depsgraph &depsgraph,
BKE_subdiv_ccg_neighbor_coords_get(
subdiv_ccg, SubdivCCGCoord{grid, x, y}, false, neighbors);
for (const SubdivCCGCoord neighbor : neighbors.coords) {
float3 disp_n = CCG_grid_elem_co(
key, elems[neighbor.grid_index], neighbor.x, neighbor.y) -
position;
float3 disp_n = vert_positions[neighbor.to_index(key)] - position;
disp_n *= ss.filter_cache->sharpen_factor[neighbor.to_index(key)];
disp_sharpen += disp_n;
}
@@ -2074,13 +2072,11 @@ static void calc_limit_surface_positions(const Object &object, MutableSpan<float
const SculptSession &ss = *object.sculpt;
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
threading::parallel_for(elems.index_range(), 512, [&](const IndexRange range) {
threading::parallel_for(IndexRange(subdiv_ccg.grids_num), 512, [&](const IndexRange range) {
for (const int grid : range) {
const int start = grid * key.grid_area;
BKE_subdiv_ccg_eval_limit_positions(
subdiv_ccg, key, grid, limit_positions.slice(start, key.grid_area));
MutableSpan grid_dst = limit_positions.slice(bke::ccg::grid_range(key, grid));
BKE_subdiv_ccg_eval_limit_positions(subdiv_ccg, key, grid, grid_dst);
}
});
}

View File

@@ -175,8 +175,7 @@ void FillDataGrids::add_initial_with_symmetry(const Object &object,
else {
BLI_assert(radius > 0.0f);
const float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
CCGElem *elem = subdiv_ccg.grids[vertex.grid_index];
float3 location = symmetry_flip(CCG_grid_elem_co(key, elem, vertex.x, vertex.y),
float3 location = symmetry_flip(subdiv_ccg.positions[vertex.to_index(key)],
ePaintSymmetryFlags(i));
vert_to_add = nearest_vert_calc_grids(pbvh, subdiv_ccg, location, radius_squared, false);
}

View File

@@ -78,12 +78,13 @@ void write_mask_mesh(const Depsgraph &depsgraph,
mask.finish();
}
static void init_mask_grids(Main &bmain,
Scene &scene,
Depsgraph &depsgraph,
Object &object,
const IndexMask &node_mask,
FunctionRef<void(const BitGroupVector<> &, int, CCGElem *)> write_fn)
static void init_mask_grids(
Main &bmain,
Scene &scene,
Depsgraph &depsgraph,
Object &object,
const IndexMask &node_mask,
FunctionRef<void(const BitGroupVector<> &, int, MutableSpan<float>)> write_fn)
{
MultiresModifierData *mmd = BKE_sculpt_multires_active(&scene, &object);
BKE_sculpt_mask_layers_ensure(&depsgraph, &bmain, &object, mmd);
@@ -92,14 +93,15 @@ static void init_mask_grids(Main &bmain,
bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const Span<CCGElem *> grids = subdiv_ccg.grids;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
MutableSpan<float> masks = subdiv_ccg.masks;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
undo::push_nodes(depsgraph, object, node_mask, undo::Type::Mask);
node_mask.foreach_index(GrainSize(1), [&](const int i) {
for (const int grid : nodes[i].grids()) {
write_fn(grid_hidden, grid, grids[grid]);
write_fn(grid_hidden, grid, masks.slice(bke::ccg::grid_range(key, grid)));
}
BKE_pbvh_node_mark_update_mask(nodes[i]);
});
@@ -169,19 +171,20 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
switch (mode) {
case InitMode::Random: {
init_mask_grids(
bmain,
scene,
depsgraph,
ob,
node_mask,
[&](const BitGroupVector<> &grid_hidden, const int grid_index, CCGElem *grid) {
const int verts_start = grid_index * key.grid_area;
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
CCG_elem_offset_mask(key, grid, i) = BLI_hash_int_01(verts_start + i + seed);
});
});
init_mask_grids(bmain,
scene,
depsgraph,
ob,
node_mask,
[&](const BitGroupVector<> &grid_hidden,
const int grid_index,
MutableSpan<float> grid_masks) {
const int verts_start = grid_index * key.grid_area;
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
grid_masks[i] = BLI_hash_int_01(verts_start + i + seed);
});
});
break;
}
case InitMode::FaceSet: {
@@ -196,32 +199,33 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
depsgraph,
ob,
node_mask,
[&](const BitGroupVector<> &grid_hidden, const int grid_index, CCGElem *grid) {
[&](const BitGroupVector<> &grid_hidden,
const int grid_index,
MutableSpan<float> grid_masks) {
const int face_set = face_sets[grid_to_face[grid_index]];
const float value = BLI_hash_int_01(face_set + seed);
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
CCG_elem_offset_mask(key, grid, i) = value;
});
key, grid_hidden, grid_index, [&](const int i) { grid_masks[i] = value; });
});
break;
}
case InitMode::Island: {
islands::ensure_cache(ob);
init_mask_grids(
bmain,
scene,
depsgraph,
ob,
node_mask,
[&](const BitGroupVector<> &grid_hidden, const int grid_index, CCGElem *grid) {
const int verts_start = grid_index * key.grid_area;
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
const int island = islands::vert_id_get(ss, verts_start + i);
CCG_elem_offset_mask(key, grid, i) = BLI_hash_int_01(island + seed);
});
});
init_mask_grids(bmain,
scene,
depsgraph,
ob,
node_mask,
[&](const BitGroupVector<> &grid_hidden,
const int grid_index,
MutableSpan<float> grid_masks) {
const int verts_start = grid_index * key.grid_area;
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
const int island = islands::vert_id_get(ss, verts_start + i);
grid_masks[i] = BLI_hash_int_01(island + seed);
});
});
break;
}
}

View File

@@ -394,25 +394,24 @@ static void grow_factors_grids(const ePaintSymmetryFlags symm,
PoseGrowFactorData &gftd)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const Span<int> grids = node.grids();
for (const int i : grids.index_range()) {
const int grid = grids[i];
CCGElem *elem = elems[grid];
const int start = key.grid_area * grid;
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
for (const short y : IndexRange(key.grid_size)) {
for (const short x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
continue;
}
const int vert = start + offset;
const int vert = grid_range[offset];
SubdivCCGNeighbors neighbors;
BKE_subdiv_ccg_neighbor_coords_get(
subdiv_ccg, SubdivCCGCoord{grids[i], x, y}, false, neighbors);
subdiv_ccg, SubdivCCGCoord{grid, x, y}, false, neighbors);
float max = 0.0f;
for (const SubdivCCGCoord neighbor : neighbors.coords) {
@@ -425,7 +424,7 @@ static void grow_factors_grids(const ePaintSymmetryFlags symm,
}
if (max > prev_mask[vert]) {
const float3 &position = CCG_elem_offset_co(key, elem, offset);
const float3 &position = positions[vert];
pose_factor[vert] = max;
if (SCULPT_check_vertex_pivot_symmetry(position, pose_initial_position, symm)) {
gftd.pos_avg += position;
@@ -821,11 +820,10 @@ static void calc_pose_origin_and_factor_grids(Object &object,
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
const Span<CCGElem *> grids = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int num_grids = key.grid_area * grids.size();
/* Calculate the pose rotation point based on the boundaries of the brush factor. */
flood_fill::FillDataGrids flood(num_grids);
flood_fill::FillDataGrids flood(positions.size());
flood.add_initial_with_symmetry(
object, pbvh, subdiv_ccg, std::get<SubdivCCGCoord>(ss.active_vert()), radius);
@@ -840,7 +838,7 @@ static void calc_pose_origin_and_factor_grids(Object &object,
r_pose_factor[to_v_i] = 1.0f;
const float3 co = CCG_grid_elem_co(key, grids[to_v.grid_index], to_v.x, to_v.y);
const float3 &co = positions[to_v_i];
if (math::distance_squared(initial_location, fallback_floodfill_origin) <
math::distance_squared(initial_location, co))
{

View File

@@ -96,51 +96,17 @@ template void neighbor_data_average_mesh<float4>(Span<float4>,
MutableSpan<float4>);
static float3 average_positions(const CCGKey &key,
const Span<CCGElem *> elems,
const Span<float3> positions,
const Span<SubdivCCGCoord> coords)
{
const float factor = math::rcp(float(coords.size()));
float3 result(0);
for (const SubdivCCGCoord coord : coords) {
result += CCG_grid_elem_co(key, elems[coord.grid_index], coord.x, coord.y) * factor;
result += positions[coord.to_index(key)] * factor;
}
return result;
}
void neighbor_position_average_grids(const SubdivCCG &subdiv_ccg,
const Span<int> grids,
const MutableSpan<float3> new_positions)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
BLI_assert(grids.size() * key.grid_area == new_positions.size());
for (const int i : grids.index_range()) {
const int grid = grids[i];
const int node_verts_start = i * key.grid_area;
/* TODO: This loop could be optimized in the future by skipping unnecessary logic for
* non-boundary grid vertices. */
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert_index = node_verts_start + offset;
SubdivCCGCoord coord{};
coord.grid_index = grid;
coord.x = x;
coord.y = y;
SubdivCCGNeighbors neighbors;
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
new_positions[node_vert_index] = average_positions(key, elems, neighbors.coords);
}
}
}
}
void neighbor_position_average_interior_grids(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const BitSpan boundary_verts,
@@ -149,14 +115,14 @@ void neighbor_position_average_interior_grids(const OffsetIndices<int> faces,
const MutableSpan<float3> new_positions)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
BLI_assert(grids.size() * key.grid_area == new_positions.size());
for (const int i : grids.index_range()) {
const int grid = grids[i];
CCGElem *elem = elems[grid];
const int node_verts_start = i * key.grid_area;
const int grid = grids[i];
const IndexRange grid_range = bke::ccg::grid_range(key, grid);
/* TODO: This loop could be optimized in the future by skipping unnecessary logic for
* non-boundary grid vertices. */
@@ -164,6 +130,7 @@ void neighbor_position_average_interior_grids(const OffsetIndices<int> faces,
for (const int x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert_index = node_verts_start + offset;
const int vert = grid_range[offset];
SubdivCCGCoord coord{};
coord.grid_index = grid;
@@ -190,10 +157,10 @@ void neighbor_position_average_interior_grids(const OffsetIndices<int> faces,
}
if (neighbors.coords.is_empty()) {
new_positions[node_vert_index] = CCG_elem_offset_co(key, elem, offset);
new_positions[node_vert_index] = positions[vert];
}
else {
new_positions[node_vert_index] = average_positions(key, elems, neighbors.coords);
new_positions[node_vert_index] = average_positions(key, positions, neighbors.coords);
}
}
}
@@ -446,40 +413,18 @@ static float3 calc_boundary_normal_corner(const float3 &current_position,
}
static float3 calc_boundary_normal_corner(const CCGKey &key,
const Span<CCGElem *> elems,
const Span<float3> positions,
const float3 &current_position,
const Span<SubdivCCGCoord> neighbors)
{
float3 normal(0);
for (const SubdivCCGCoord &coord : neighbors) {
const float3 to_neighbor = CCG_grid_elem_co(key, elems[coord.grid_index], coord.x, coord.y) -
current_position;
const float3 to_neighbor = positions[coord.to_index(key)] - current_position;
normal += math::normalize(to_neighbor);
}
return math::normalize(normal);
}
static float3 average_positions(const CCGKey &key,
const Span<CCGElem *> elems,
const Span<float3> positions,
const Span<SubdivCCGCoord> neighbors,
const int current_grid,
const int current_grid_start)
{
const float factor = math::rcp(float(neighbors.size()));
float3 result(0);
for (const SubdivCCGCoord &coord : neighbors) {
if (current_grid == coord.grid_index) {
const int offset = CCG_grid_xy_to_index(key.grid_size, coord.x, coord.y);
result += positions[current_grid_start + offset] * factor;
}
else {
result += CCG_grid_elem_co(key, elems[coord.grid_index], coord.x, coord.y) * factor;
}
}
return result;
}
static float3 calc_boundary_normal_corner(const float3 &current_position,
const Span<BMVert *> neighbors)
{
@@ -572,11 +517,11 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
const Span<int> grids,
const bool filter_boundary_face_sets,
const Span<float> factors,
const Span<float3> positions,
Vector<Vector<SubdivCCGCoord>> &neighbors,
const MutableSpan<float3> translations)
{
const Span<CCGElem *> elems = subdiv_ccg.grids;
const Span<float3> positions = subdiv_ccg.positions;
const Span<float3> normals = subdiv_ccg.normals;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const int grid_verts_num = grids.size() * key.grid_area;
@@ -587,12 +532,13 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
calc_vert_neighbors_interior(faces, corner_verts, boundary_verts, subdiv_ccg, grids, neighbors);
for (const int i : grids.index_range()) {
CCGElem *elem = elems[grids[i]];
const IndexRange grid_range = bke::ccg::grid_range(key, grids[i]);
const int node_start = i * key.grid_area;
for (const int y : IndexRange(key.grid_size)) {
for (const int x : IndexRange(key.grid_size)) {
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
const int node_vert = node_start + offset;
const int vert = grid_range[offset];
if (factors[node_vert] == 0.0f) {
translations[node_vert] = float3(0);
continue;
@@ -631,25 +577,24 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
continue;
}
const float3 smoothed_position = average_positions(
key, elems, positions, neighbors[node_vert], grids[i], node_start);
const float3 smoothed_position = average_positions(key, positions, neighbors[node_vert]);
/* Normal Calculation */
float3 normal;
if (is_boundary && neighbors[i].size() == 2) {
normal = calc_boundary_normal_corner(
key, elems, positions[node_vert], neighbors[node_vert]);
key, positions, positions[vert], neighbors[node_vert]);
if (math::is_zero(normal)) {
translations[node_vert] = float3(0);
continue;
}
}
else {
normal = CCG_elem_offset_no(key, elem, offset);
normal = normals[vert];
}
const float3 translation = translation_to_plane(
positions[node_vert], normal, smoothed_position);
positions[vert], normal, smoothed_position);
translations[node_vert] = translation * factors[node_vert];
}

View File

@@ -39,9 +39,6 @@ void neighbor_color_average(OffsetIndices<int> faces,
Span<Vector<int>> vert_neighbors,
MutableSpan<float4> smooth_colors);
void neighbor_position_average_grids(const SubdivCCG &subdiv_ccg,
Span<int> grids,
MutableSpan<float3> new_positions);
void neighbor_position_average_interior_grids(OffsetIndices<int> faces,
Span<int> corner_verts,
BitSpan boundary_verts,
@@ -109,7 +106,6 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
Span<int> grids,
bool filter_boundary_face_sets,
Span<float> factors,
Span<float3> positions,
Vector<Vector<SubdivCCGCoord>> &neighbors,
MutableSpan<float3> translations);
void calc_relaxed_translations_bmesh(const Set<BMVert *, 0> &verts,

View File

@@ -80,6 +80,7 @@
#include "ED_undo.hh"
#include "bmesh.hh"
#include "mesh_brush_common.hh"
#include "paint_hide.hh"
#include "paint_intern.hh"
#include "sculpt_color.hh"
@@ -418,7 +419,7 @@ static bool topology_matches(const StepData &step_data, const Object &object)
const SculptSession &ss = *object.sculpt;
if (use_multires_undo(step_data, ss)) {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
return subdiv_ccg.grids.size() == step_data.mesh_grids_num &&
return subdiv_ccg.grids_num == step_data.mesh_grids_num &&
subdiv_ccg.grid_size == step_data.grid_size;
}
Mesh &mesh = *static_cast<Mesh *>(object.data);
@@ -548,24 +549,23 @@ static void restore_position_mesh(Object &object,
}
}
static void restore_position_grids(MutableSpan<CCGElem *> grids,
static void restore_position_grids(MutableSpan<float3> positions,
const CCGKey &key,
Node &unode,
MutableSpan<bool> modified_grids)
{
const Span<int> grid_indices = unode.grids;
MutableSpan<float3> position = unode.position;
const Span<int> grids = unode.grids;
MutableSpan<float3> undo_position = unode.position;
int index = 0;
for (const int i : grid_indices.index_range()) {
CCGElem *grid = grids[grid_indices[i]];
for (const int j : IndexRange(key.grid_area)) {
std::swap(CCG_elem_offset_co(key, grid, j), position[index]);
index++;
for (const int i : grids.index_range()) {
MutableSpan data = positions.slice(bke::ccg::grid_range(key, grids[i]));
MutableSpan undo_data = undo_position.slice(bke::ccg::grid_range(key, i));
for (const int offset : data.index_range()) {
std::swap(data[offset], undo_data[offset]);
}
}
modified_grids.fill_indices(grid_indices, true);
modified_grids.fill_indices(grids, true);
}
static void restore_vert_visibility_mesh(Object &object,
@@ -681,18 +681,18 @@ static void restore_mask_grids(Object &object, Node &unode, MutableSpan<bool> mo
{
SculptSession &ss = *object.sculpt;
SubdivCCG *subdiv_ccg = ss.subdiv_ccg;
MutableSpan<float> masks = subdiv_ccg->masks;
const CCGKey key = BKE_subdiv_ccg_key_top_level(*subdiv_ccg);
MutableSpan<float> mask = unode.mask;
MutableSpan<CCGElem *> grids = subdiv_ccg->grids;
const Span<int> grids = unode.grids;
MutableSpan<float> undo_mask = unode.mask;
int index = 0;
for (const int grid : unode.grids) {
CCGElem *elem = grids[grid];
for (const int j : IndexRange(key.grid_area)) {
std::swap(CCG_elem_offset_mask(key, elem, j), mask[index]);
index++;
for (const int i : grids.index_range()) {
MutableSpan data = masks.slice(bke::ccg::grid_range(key, grids[i]));
MutableSpan undo_data = undo_mask.slice(bke::ccg::grid_range(key, i));
for (const int offset : data.index_range()) {
std::swap(data[offset], undo_data[offset]);
}
}
@@ -1001,12 +1001,11 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
if (use_multires_undo(step_data, ss)) {
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
MutableSpan<CCGElem *> grids = subdiv_ccg.grids;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
Array<bool> modified_grids(grids.size(), false);
Array<bool> modified_grids(subdiv_ccg.grids_num, false);
for (std::unique_ptr<Node> &unode : step_data.nodes) {
restore_position_grids(grids, key, *unode, modified_grids);
restore_position_grids(subdiv_ccg.positions, key, *unode, modified_grids);
}
node_mask.foreach_index([&](const int i) {
const Span<int> grids = nodes[i].grids();
@@ -1051,7 +1050,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
if (use_multires_undo(step_data, ss)) {
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
Array<bool> modified_grids(subdiv_ccg.grids.size(), false);
Array<bool> modified_grids(subdiv_ccg.grids_num, false);
for (std::unique_ptr<Node> &unode : step_data.nodes) {
restore_vert_visibility_grids(subdiv_ccg, *unode, modified_grids);
}
@@ -1133,7 +1132,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
if (use_multires_undo(step_data, ss)) {
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
Array<bool> modified_grids(ss.subdiv_ccg->grids.size(), false);
Array<bool> modified_grids(ss.subdiv_ccg->grids_num, false);
for (std::unique_ptr<Node> &unode : step_data.nodes) {
restore_mask_grids(object, *unode, modified_grids);
}
@@ -1311,29 +1310,10 @@ static void store_positions_mesh(const Depsgraph &depsgraph, const Object &objec
static void store_positions_grids(const SubdivCCG &subdiv_ccg, Node &unode)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
{
int index = 0;
for (const int grid : unode.grids) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
unode.position[index] = CCG_elem_offset_co(key, elem, i);
index++;
}
}
}
if (key.has_normals) {
int index = 0;
for (const int grid : unode.grids) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
unode.normal[index] = CCG_elem_offset_no(key, elem, i);
index++;
}
}
}
gather_data_grids(
subdiv_ccg, subdiv_ccg.positions.as_span(), unode.grids, unode.position.as_mutable_span());
gather_data_grids(
subdiv_ccg, subdiv_ccg.normals.as_span(), unode.grids, unode.normal.as_mutable_span());
}
static void store_vert_visibility_mesh(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
@@ -1378,17 +1358,9 @@ static void store_mask_mesh(const Mesh &mesh, Node &unode)
static void store_mask_grids(const SubdivCCG &subdiv_ccg, Node &unode)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (key.has_mask) {
const Span<CCGElem *> grids = subdiv_ccg.grids;
int index = 0;
for (const int grid : unode.grids) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
unode.mask[index] = CCG_elem_offset_mask(key, elem, i);
index++;
}
}
if (!subdiv_ccg.masks.is_empty()) {
gather_data_grids(
subdiv_ccg, subdiv_ccg.masks.as_span(), unode.grids, unode.mask.as_mutable_span());
}
else {
unode.mask.fill(0.0f);
@@ -1869,7 +1841,7 @@ void push_begin_ex(Object &ob, const char *name)
break;
}
case bke::pbvh::Type::Grids: {
us->data.mesh_grids_num = ss.subdiv_ccg->grids.size();
us->data.mesh_grids_num = ss.subdiv_ccg->grids_num;
us->data.grid_size = ss.subdiv_ccg->grid_size;
break;
}