Refactor: Sculpt: Specialize grab active vertex preview

The preview is only supported with deform modifiers which are
only supported for Mesh sculpting, so just write that implementation.
Also remove SculptSession::vert_positions which is now unnecessary.
This commit is contained in:
Hans Goudey
2024-08-07 22:13:18 -04:00
parent 1b29b52f2d
commit 2582858e08
6 changed files with 81 additions and 77 deletions

View File

@@ -423,7 +423,6 @@ struct SculptSession : blender::NonCopyable, blender::NonMovable {
Depsgraph *depsgraph = nullptr;
/* These are always assigned to base mesh data when using Type::Mesh. */
blender::MutableSpan<blender::float3> vert_positions;
blender::OffsetIndices<int> faces;
blender::Span<int> corner_verts;
@@ -509,8 +508,7 @@ struct SculptSession : blender::NonCopyable, blender::NonMovable {
Scene *scene = nullptr;
/* Dynamic mesh preview */
PBVHVertRef *preview_vert_list = nullptr;
int preview_vert_count = 0;
blender::Array<int> preview_verts;
/* Pose Brush Preview */
blender::float3 pose_origin;

View File

@@ -1662,8 +1662,7 @@ static void sculptsession_free_pbvh(Object *object)
ss->vert_to_edge_indices = {};
ss->vert_to_edge_map = {};
MEM_SAFE_FREE(ss->preview_vert_list);
ss->preview_vert_count = 0;
ss->preview_verts = {};
ss->vertex_info.boundary.clear_and_shrink();
@@ -1945,7 +1944,6 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss.totvert = mesh_orig->verts_num;
ss.faces_num = mesh_orig->faces_num;
ss.totfaces = mesh_orig->faces_num;
ss.vert_positions = mesh_orig->vert_positions_for_write();
ss.faces = mesh_orig->faces();
ss.corner_verts = mesh_orig->corner_verts();
ss.multires.active = false;

View File

@@ -1147,17 +1147,13 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
static void sculpt_geometry_preview_lines_draw(const uint gpuattr,
const Brush &brush,
const bool is_multires,
const SculptSession &ss)
const Object &object)
{
if (!(brush.flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
return;
}
if (is_multires) {
return;
}
const SculptSession &ss = *object.sculpt;
if (ss.pbvh->type() != bke::pbvh::Type::Mesh) {
return;
}
@@ -1175,10 +1171,11 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr,
}
GPU_line_width(1.0f);
if (ss.preview_vert_count > 0) {
immBegin(GPU_PRIM_LINES, ss.preview_vert_count);
for (int i = 0; i < ss.preview_vert_count; i++) {
immVertex3fv(gpuattr, SCULPT_vertex_co_for_grab_active_get(ss, ss.preview_vert_list[i]));
if (!ss.preview_verts.is_empty()) {
const Span<float3> positions = vert_positions_for_grab_active_get(object);
immBegin(GPU_PRIM_LINES, ss.preview_verts.size());
for (const int vert : ss.preview_verts) {
immVertex3fv(gpuattr, positions[vert]);
}
immEnd();
}
@@ -1258,7 +1255,6 @@ struct PaintCursorContext {
bool is_stroke_active;
bool is_cursor_over_mesh;
bool is_multires;
float radius;
/* 3D view cursor position and normal. */
@@ -1434,8 +1430,6 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
paint_cursor_update_unprojected_radius(ups, brush, vc, pcontext->scene_space_location);
}
pcontext->is_multires = ss.pbvh != nullptr && ss.pbvh->type() == bke::pbvh::Type::Grids;
pcontext->sd = CTX_data_tool_settings(pcontext->C)->sculpt;
}
@@ -1769,7 +1763,14 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
const float *active_vertex_co;
if (brush.sculpt_tool == SCULPT_TOOL_GRAB && brush.flag & BRUSH_GRAB_ACTIVE_VERTEX) {
active_vertex_co = SCULPT_vertex_co_for_grab_active_get(*pcontext->ss, active_vert);
SculptSession &ss = *pcontext->ss;
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
const Span<float3> positions = vert_positions_for_grab_active_get(*pcontext->vc.obact);
active_vertex_co = positions[active_vert.i];
}
else {
active_vertex_co = SCULPT_vertex_co_get(*pcontext->ss, active_vert);
}
}
else {
active_vertex_co = SCULPT_vertex_co_get(*pcontext->ss, active_vert);
@@ -1846,8 +1847,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
(brush.flag & BRUSH_GRAB_ACTIVE_VERTEX))
{
geometry_preview_lines_update(pcontext->C, *pcontext->ss, pcontext->radius);
sculpt_geometry_preview_lines_draw(
pcontext->pos, *pcontext->brush, pcontext->is_multires, *pcontext->ss);
sculpt_geometry_preview_lines_draw(pcontext->pos, *pcontext->brush, *pcontext->vc.obact);
}
if (is_brush_tool && brush.sculpt_tool == SCULPT_TOOL_POSE) {
@@ -1937,7 +1937,7 @@ static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorCont
/* Draw the special active cursors different tools may have. */
if (brush.sculpt_tool == SCULPT_TOOL_GRAB) {
sculpt_geometry_preview_lines_draw(pcontext->pos, brush, pcontext->is_multires, ss);
sculpt_geometry_preview_lines_draw(pcontext->pos, brush, *pcontext->vc.obact);
}
if (brush.sculpt_tool == SCULPT_TOOL_MULTIPLANE_SCRAPE) {

View File

@@ -203,23 +203,23 @@ const blender::float3 SCULPT_vertex_normal_get(const SculptSession &ss, PBVHVert
return {};
}
const float *SCULPT_vertex_co_for_grab_active_get(const SculptSession &ss, PBVHVertRef vertex)
namespace blender::ed::sculpt_paint {
Span<float3> vert_positions_for_grab_active_get(const Object &object)
{
if (ss.pbvh->type() == blender::bke::pbvh::Type::Mesh) {
const SculptSession &ss = *object.sculpt;
BLI_assert(ss.pbvh->type() == bke::pbvh::Type::Mesh);
if (ss.shapekey_active) {
/* Always grab active shape key if the sculpt happens on shapekey. */
if (ss.shapekey_active) {
const Span<float3> positions = BKE_pbvh_get_vert_positions(*ss.pbvh);
return positions[vertex.i];
}
/* Sculpting on the base mesh. */
return ss.vert_positions[vertex.i];
return BKE_pbvh_get_vert_positions(*ss.pbvh);
}
/* Everything else, such as sculpting on multires. */
return SCULPT_vertex_co_get(ss, vertex);
/* Otherwise use the base mesh positions. */
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
return mesh.vert_positions();
}
} // namespace blender::ed::sculpt_paint
float *SCULPT_brush_deform_target_vertex_co_get(SculptSession &ss,
const int deform_target,
PBVHVertexIter *iter)
@@ -4612,7 +4612,9 @@ static bool sculpt_needs_delta_for_tip_orientation(const Brush &brush)
SCULPT_TOOL_SNAKE_HOOK);
}
static void sculpt_update_brush_delta(UnifiedPaintSettings &ups, Object &ob, const Brush &brush)
static void sculpt_update_brush_delta(UnifiedPaintSettings &ups,
const Object &ob,
const Brush &brush)
{
SculptSession &ss = *ob.sculpt;
StrokeCache *cache = ss.cache;
@@ -4645,8 +4647,13 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings &ups, Object &ob, con
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache)) {
if (tool == SCULPT_TOOL_GRAB && brush.flag & BRUSH_GRAB_ACTIVE_VERTEX) {
copy_v3_v3(cache->orig_grab_location,
SCULPT_vertex_co_for_grab_active_get(ss, ss.active_vert_ref()));
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
const Span<float3> positions = vert_positions_for_grab_active_get(ob);
cache->orig_grab_location = positions[ss.active_vert_ref().i];
}
else {
cache->orig_grab_location = SCULPT_vertex_co_get(ss, ss.active_vert_ref());
}
}
else {
copy_v3_v3(cache->orig_grab_location, cache->true_location);

View File

@@ -902,10 +902,14 @@ const blender::float3 SCULPT_vertex_normal_get(const SculptSession &ss, PBVHVert
bool SCULPT_vertex_is_occluded(SculptSession &ss, PBVHVertRef vertex, bool original);
namespace blender::ed::sculpt_paint {
/**
* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
*/
const float *SCULPT_vertex_co_for_grab_active_get(const SculptSession &ss, PBVHVertRef vertex);
Span<float3> vert_positions_for_grab_active_get(const Object &object);
}
/**
* Returns the pointer to the coordinates that should be edited from a brush tool iterator

View File

@@ -581,8 +581,7 @@ void geometry_preview_lines_update(bContext *C, SculptSession &ss, float radius)
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
ss.preview_vert_count = 0;
int totpoints = 0;
ss.preview_verts = {};
/* This function is called from the cursor drawing code, so the tree may not be build yet. */
if (!ss.pbvh) {
@@ -593,54 +592,52 @@ void geometry_preview_lines_update(bContext *C, SculptSession &ss, float radius)
return;
}
if (ss.pbvh->type() == bke::pbvh::Type::Grids) {
if (ss.pbvh->type() != bke::pbvh::Type::Mesh) {
return;
}
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
float brush_co[3];
copy_v3_v3(brush_co, SCULPT_vertex_co_get(ss, ss.active_vert_ref()));
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
/* Always grab active shape key if the sculpt happens on shapekey. */
const Span<float3> positions = ss.shapekey_active ? BKE_pbvh_get_vert_positions(*ss.pbvh) :
mesh.vert_positions();
const OffsetIndices faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts();
const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
const bke::AttributeAccessor attributes = mesh.attributes();
const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
BitVector<> visited_verts(SCULPT_vertex_count_get(ss));
const int active_vert = ss.active_vert_ref().i;
const float3 brush_co = positions[active_vert];
const float radius_sq = radius * radius;
/* Assuming an average of 6 edges per vertex in a triangulated mesh. */
const int max_preview_verts = SCULPT_vertex_count_get(ss) * 3 * 2;
Vector<int> preview_verts;
Vector<int> neighbors;
BitVector<> visited_verts(positions.size());
std::queue<int> queue;
queue.push(active_vert);
while (!queue.empty()) {
const int from_vert = queue.front();
queue.pop();
if (ss.preview_vert_list == nullptr) {
ss.preview_vert_list = MEM_cnew_array<PBVHVertRef>(max_preview_verts, __func__);
}
std::queue<PBVHVertRef> non_visited_verts;
non_visited_verts.push(ss.active_vert_ref());
while (!non_visited_verts.empty()) {
PBVHVertRef from_v = non_visited_verts.front();
non_visited_verts.pop();
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
if (totpoints + (ni.neighbors.size() * 2) < max_preview_verts) {
PBVHVertRef to_v = ni.vertex;
int to_v_i = ni.index;
ss.preview_vert_list[totpoints] = from_v;
totpoints++;
ss.preview_vert_list[totpoints] = to_v;
totpoints++;
if (visited_verts[to_v_i]) {
continue;
}
visited_verts[to_v_i].set();
const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
if (len_squared_v3v3(brush_co, co) < radius * radius) {
non_visited_verts.push(to_v);
}
neighbors.clear();
for (const int neighbor : vert_neighbors_get_mesh(
from_vert, faces, corner_verts, vert_to_face_map, hide_poly, neighbors))
{
preview_verts.append(from_vert);
preview_verts.append(neighbor);
if (visited_verts[neighbor]) {
continue;
}
visited_verts[neighbor].set();
if (math::distance_squared(brush_co, positions[neighbor]) < radius_sq) {
queue.push(neighbor);
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
ss.preview_vert_count = totpoints;
ss.preview_verts = preview_verts.as_span();
}
static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)