Sculpt: Initial data oriented refactor for multires displacement eraser
Part of #118145. Since only multires was supported, this was simpler. The grid iteration has more boilerplate code than I'd like, but that can be improved later on. Use of the "proxy" system is unnecessary here (as it is in general) and it's removed in this commit. Pull Request: https://projects.blender.org/blender/blender/pulls/123101
This commit is contained in:
@@ -120,6 +120,7 @@ set(SRC
|
||||
brushes/fill.cc
|
||||
brushes/flatten.cc
|
||||
brushes/inflate.cc
|
||||
brushes/multires_displacement_eraser.cc
|
||||
brushes/scrape.cc
|
||||
brushes/smooth.cc
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "editors/sculpt_paint/brushes/types.hh"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_paint.hh"
|
||||
#include "BKE_pbvh.hh"
|
||||
#include "BKE_subdiv_ccg.hh"
|
||||
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "editors/sculpt_paint/mesh_brush_common.hh"
|
||||
#include "editors/sculpt_paint/sculpt_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
inline namespace multires_displacement_eraser_cc {
|
||||
|
||||
static void calc_node(
|
||||
const Sculpt &sd, Object &object, const Brush &brush, const float strength, PBVHNode &node)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
|
||||
SculptBrushTest test;
|
||||
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
|
||||
ss, test, brush.falloff_shape);
|
||||
const int thread_id = BLI_task_parallel_thread_id(nullptr);
|
||||
auto_mask::NodeData automask_data = auto_mask::node_begin(
|
||||
object, ss.cache->automasking.get(), node);
|
||||
|
||||
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
||||
const CCGKey key = *BKE_pbvh_get_grid_key(*ss.pbvh);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
||||
|
||||
int i = 0;
|
||||
for (const int grid : bke::pbvh::node_grid_indices(node)) {
|
||||
const int grid_verts_start = grid * key.grid_area;
|
||||
CCGElem *elem = grids[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);
|
||||
if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
float3 &co = CCG_elem_offset_co(key, elem, offset);
|
||||
if (!sculpt_brush_test_sq_fn(test, co)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
auto_mask::node_update(automask_data, i);
|
||||
const float fade = SCULPT_brush_strength_factor(
|
||||
ss,
|
||||
brush,
|
||||
co,
|
||||
math::sqrt(test.dist),
|
||||
CCG_elem_offset_no(key, elem, offset),
|
||||
nullptr,
|
||||
key.has_mask ? CCG_elem_offset_mask(key, elem, offset) : 0.0f,
|
||||
BKE_pbvh_make_vref(grid_verts_start + offset),
|
||||
thread_id,
|
||||
&automask_data);
|
||||
|
||||
SubdivCCGCoord coord{};
|
||||
coord.grid_index = grid;
|
||||
coord.x = x;
|
||||
coord.y = y;
|
||||
float3 limit_co;
|
||||
BKE_subdiv_ccg_eval_limit_point(*ss.subdiv_ccg, coord, limit_co);
|
||||
|
||||
const float3 translation = (limit_co - co) * fade * strength;
|
||||
|
||||
SCULPT_clip(sd, ss, co, co + translation);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace multires_displacement_eraser_cc
|
||||
|
||||
void do_displacement_eraser_brush(const Sculpt &sd, Object &object, Span<PBVHNode *> nodes)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
|
||||
const float strength = std::min(ss.cache->bstrength, 1.0f);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
calc_node(sd, object, brush, strength, *nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
@@ -24,6 +24,7 @@ void do_smooth_brush(const Sculpt &sd,
|
||||
float brush_strength);
|
||||
void do_scrape_brush(const Sculpt &sd, Object &object, Span<PBVHNode *> nodes);
|
||||
void do_fill_brush(const Sculpt &sd, Object &object, Span<PBVHNode *> nodes);
|
||||
void do_displacement_eraser_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_flatten_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_inflate_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
|
||||
|
||||
@@ -3866,7 +3866,7 @@ static void do_brush_action(const Sculpt &sd,
|
||||
face_set::do_draw_face_sets_brush(sd, ob, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_DISPLACEMENT_ERASER:
|
||||
SCULPT_do_displacement_eraser_brush(sd, ob, nodes);
|
||||
do_displacement_eraser_brush(sd, ob, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
|
||||
SCULPT_do_displacement_smear_brush(sd, ob, nodes);
|
||||
@@ -6006,9 +6006,9 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
|
||||
{
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (brush.sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR) {
|
||||
if (!ss.pbvh || BKE_pbvh_type(*ss.pbvh) == PBVH_BMESH) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not supported in dynamic topology mode");
|
||||
if (ELEM(brush.sculpt_tool, SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_DISPLACEMENT_ERASER)) {
|
||||
if (!ss.pbvh || BKE_pbvh_type(*ss.pbvh) != PBVH_GRIDS) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Only supported in multiresolution mode");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1703,67 +1703,6 @@ void SCULPT_do_slide_relax_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *>
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sculpt Multires Displacement Eraser Brush
|
||||
* \{ */
|
||||
|
||||
static void do_displacement_eraser_brush_task(Object &ob, const Brush &brush, PBVHNode *node)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
const float bstrength = clamp_f(ss.cache->bstrength, 0.0f, 1.0f);
|
||||
|
||||
const MutableSpan<float3> proxy = BKE_pbvh_node_add_proxy(*ss.pbvh, *node).co;
|
||||
|
||||
SculptBrushTest test;
|
||||
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
|
||||
ss, test, brush.falloff_shape);
|
||||
const int thread_id = BLI_task_parallel_thread_id(nullptr);
|
||||
|
||||
auto_mask::NodeData automask_data = auto_mask::node_begin(
|
||||
ob, ss.cache->automasking.get(), *node);
|
||||
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (*ss.pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
if (!sculpt_brush_test_sq_fn(test, vd.co)) {
|
||||
continue;
|
||||
}
|
||||
auto_mask::node_update(automask_data, vd);
|
||||
|
||||
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
|
||||
brush,
|
||||
vd.co,
|
||||
sqrtf(test.dist),
|
||||
vd.no,
|
||||
vd.fno,
|
||||
vd.mask,
|
||||
vd.vertex,
|
||||
thread_id,
|
||||
&automask_data);
|
||||
|
||||
float3 limit_co = SCULPT_vertex_limit_surface_get(ss, vd.vertex);
|
||||
float disp[3];
|
||||
sub_v3_v3v3(disp, limit_co, vd.co);
|
||||
mul_v3_v3fl(proxy[vd.i], disp, fade);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
void SCULPT_do_displacement_eraser_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes)
|
||||
{
|
||||
using namespace blender;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
|
||||
BKE_curvemapping_init(brush.curve);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
do_displacement_eraser_brush_task(ob, brush, nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sculpt Multires Displacement Smear Brush
|
||||
* \{ */
|
||||
|
||||
@@ -2032,9 +2032,6 @@ void SCULPT_do_slide_relax_brush(const Sculpt &sd, Object &ob, blender::Span<PBV
|
||||
void SCULPT_do_displacement_smear_brush(const Sculpt &sd,
|
||||
Object &ob,
|
||||
blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_displacement_eraser_brush(const Sculpt &sd,
|
||||
Object &ob,
|
||||
blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_mask_brush_draw(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_mask_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
/** \} */
|
||||
|
||||
Reference in New Issue
Block a user