Sculpt: Initial data oriented refactor for crease/blob brushes
Part of #118145. I added a scene argument to the brush symmetry operation functions. Besides that, the changes here are just like the other refactors. Pull Request: https://projects.blender.org/blender/blender/pulls/123231
This commit is contained in:
@@ -116,6 +116,7 @@ set(SRC
|
||||
sculpt_intern.hh
|
||||
|
||||
brushes/clay_strips.cc
|
||||
brushes/crease.cc
|
||||
brushes/draw_vector_displacement.cc
|
||||
brushes/draw.cc
|
||||
brushes/fill.cc
|
||||
|
||||
341
source/blender/editors/sculpt_paint/brushes/crease.cc
Normal file
341
source/blender/editors/sculpt_paint/brushes/crease.cc
Normal file
@@ -0,0 +1,341 @@
|
||||
/* 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_brush.hh"
|
||||
#include "BKE_key.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_paint.hh"
|
||||
#include "BKE_pbvh.hh"
|
||||
#include "BKE_subdiv_ccg.hh"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_enumerable_thread_specific.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#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 crease_cc {
|
||||
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
|
||||
BLI_NOINLINE static void translations_from_position(const Span<float3> positions_eval,
|
||||
const Span<int> verts,
|
||||
const float3 &location,
|
||||
const MutableSpan<float3> translations)
|
||||
{
|
||||
for (const int i : verts.index_range()) {
|
||||
translations[i] = location - positions_eval[verts[i]];
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void project_translations(const MutableSpan<float3> translations,
|
||||
const float3 &plane)
|
||||
{
|
||||
/* Equivalent to #project_plane_v3_v3v3. */
|
||||
const float len_sq = math::length_squared(plane);
|
||||
if (len_sq < std::numeric_limits<float>::epsilon()) {
|
||||
return;
|
||||
}
|
||||
const float dot_factor = -math::rcp(len_sq);
|
||||
for (const int i : translations.index_range()) {
|
||||
translations[i] += plane * math::dot(translations[i], plane) * dot_factor;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void add_offset_to_translations(const MutableSpan<float3> translations,
|
||||
const Span<float> factors,
|
||||
const float3 &offset)
|
||||
{
|
||||
for (const int i : translations.index_range()) {
|
||||
translations[i] += offset * factors[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_faces(const Sculpt &sd,
|
||||
const Brush &brush,
|
||||
const float3 &offset,
|
||||
const float strength,
|
||||
const Span<float3> positions_eval,
|
||||
const Span<float3> vert_normals,
|
||||
const PBVHNode &node,
|
||||
Object &object,
|
||||
LocalData &tls,
|
||||
const MutableSpan<float3> positions_orig)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const StrokeCache &cache = *ss.cache;
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
|
||||
tls.factors.reinitialize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(mesh, verts, factors);
|
||||
|
||||
if (brush.flag & BRUSH_FRONTFACE) {
|
||||
calc_front_face(cache.view_normal, vert_normals, verts, factors);
|
||||
}
|
||||
|
||||
tls.distances.reinitialize(verts.size());
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
calc_distance_falloff(
|
||||
ss, positions_eval, verts, eBrushFalloffShape(brush.falloff_shape), distances, factors);
|
||||
calc_brush_strength_factors(cache, brush, distances, factors);
|
||||
|
||||
if (cache.automasking) {
|
||||
auto_mask::calc_vert_factors(object, *cache.automasking, node, verts, factors);
|
||||
}
|
||||
|
||||
calc_brush_texture_factors(ss, brush, positions_eval, verts, factors);
|
||||
|
||||
tls.translations.reinitialize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
translations_from_position(positions_eval, verts, cache.location, translations);
|
||||
|
||||
if (brush.falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
|
||||
project_translations(translations, cache.view_normal);
|
||||
}
|
||||
|
||||
scale_translations(translations, factors);
|
||||
scale_translations(translations, strength);
|
||||
|
||||
/* The vertices are pinched towards a line instead of a single point. Without this we get a
|
||||
* 'flat' surface surrounding the pinch. */
|
||||
project_translations(translations, cache.sculpt_normal_symm);
|
||||
|
||||
add_offset_to_translations(translations, factors, offset);
|
||||
|
||||
write_translations(sd, object, positions_eval, verts, translations, positions_orig);
|
||||
}
|
||||
|
||||
static void calc_grids(
|
||||
Object &object, const Brush &brush, const float3 &offset, const float strength, PBVHNode &node)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const StrokeCache &cache = *ss.cache;
|
||||
const float3 &location = cache.location;
|
||||
|
||||
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;
|
||||
|
||||
/* TODO: Remove usage of proxies. */
|
||||
const MutableSpan<float3> proxy = BKE_pbvh_node_add_proxy(*ss.pbvh, node).co;
|
||||
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 j : IndexRange(key.grid_area)) {
|
||||
if (!grid_hidden.is_empty() && grid_hidden[grid][j]) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
const float3 &co = CCG_elem_offset_co(key, elem, j);
|
||||
if (!sculpt_brush_test_sq_fn(test, co)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float3 translation = location - co;
|
||||
if (brush.falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
|
||||
project_translations({&translation, 1}, cache.view_normal);
|
||||
}
|
||||
|
||||
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, j),
|
||||
nullptr,
|
||||
key.has_mask ? CCG_elem_offset_mask(key, elem, j) : 0.0f,
|
||||
BKE_pbvh_make_vref(grid_verts_start + j),
|
||||
thread_id,
|
||||
&automask_data);
|
||||
|
||||
translation *= fade;
|
||||
translation *= strength;
|
||||
|
||||
/* The vertices are pinched towards a line instead of a single point. Without this we get a
|
||||
* 'flat' surface surrounding the pinch. */
|
||||
project_translations({&translation, 1}, cache.sculpt_normal_symm);
|
||||
|
||||
translation += offset * fade;
|
||||
|
||||
proxy[i] = translation;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_bmesh(
|
||||
Object &object, const Brush &brush, const float3 &offset, const float strength, PBVHNode &node)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const StrokeCache &cache = *ss.cache;
|
||||
const float3 &location = cache.location;
|
||||
|
||||
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);
|
||||
|
||||
const int mask_offset = CustomData_get_offset_named(
|
||||
&ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
|
||||
/* TODO: Remove usage of proxies. */
|
||||
const MutableSpan<float3> proxy = BKE_pbvh_node_add_proxy(*ss.pbvh, node).co;
|
||||
int i = 0;
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(&node)) {
|
||||
if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!sculpt_brush_test_sq_fn(test, vert->co)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float3 translation = location - float3(vert->co);
|
||||
if (brush.falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
|
||||
project_translations({&translation, 1}, cache.view_normal);
|
||||
}
|
||||
|
||||
auto_mask::node_update(automask_data, i);
|
||||
const float mask = mask_offset == -1 ? 0.0f : BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
|
||||
const float fade = SCULPT_brush_strength_factor(ss,
|
||||
brush,
|
||||
vert->co,
|
||||
math::sqrt(test.dist),
|
||||
vert->no,
|
||||
nullptr,
|
||||
mask,
|
||||
BKE_pbvh_make_vref(intptr_t(vert)),
|
||||
thread_id,
|
||||
&automask_data);
|
||||
|
||||
translation *= fade;
|
||||
translation *= strength;
|
||||
|
||||
/* The vertices are pinched towards a line instead of a single point. Without this we get a
|
||||
* 'flat' surface surrounding the pinch. */
|
||||
project_translations({&translation, 1}, cache.sculpt_normal_symm);
|
||||
|
||||
translation += offset * fade;
|
||||
|
||||
proxy[i] = translation;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_crease_or_blob_brush(const Scene &scene,
|
||||
const Sculpt &sd,
|
||||
const bool invert_strength,
|
||||
Object &object,
|
||||
Span<PBVHNode *> nodes)
|
||||
{
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const StrokeCache &cache = *ss.cache;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
|
||||
|
||||
/* Offset with as much as possible factored in already. */
|
||||
const float3 offset = cache.sculpt_normal_symm * cache.scale * cache.radius * cache.bstrength;
|
||||
|
||||
/* We divide out the squared alpha and multiply by the squared crease
|
||||
* to give us the pinch strength. */
|
||||
float crease_correction = brush.crease_pinch_factor * brush.crease_pinch_factor;
|
||||
float brush_alpha = BKE_brush_alpha_get(&scene, &brush);
|
||||
if (brush_alpha > 0.0f) {
|
||||
crease_correction /= brush_alpha * brush_alpha;
|
||||
}
|
||||
|
||||
/* We always want crease to pinch or blob to relax even when draw is negative. */
|
||||
const float strength = std::abs(cache.bstrength) * crease_correction *
|
||||
(invert_strength ? -1.0f : 1.0f);
|
||||
|
||||
switch (BKE_pbvh_type(*object.sculpt->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
threading::EnumerableThreadSpecific<LocalData> all_tls;
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
const PBVH &pbvh = *ss.pbvh;
|
||||
const Span<float3> positions_eval = BKE_pbvh_get_vert_positions(pbvh);
|
||||
const Span<float3> vert_normals = BKE_pbvh_get_vert_normals(pbvh);
|
||||
MutableSpan<float3> positions_orig = mesh.vert_positions_for_write();
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
calc_faces(sd,
|
||||
brush,
|
||||
offset,
|
||||
strength,
|
||||
positions_eval,
|
||||
vert_normals,
|
||||
*nodes[i],
|
||||
object,
|
||||
tls,
|
||||
positions_orig);
|
||||
BKE_pbvh_node_mark_positions_update(nodes[i]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS:
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
calc_grids(object, brush, offset, strength, *nodes[i]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
calc_bmesh(object, brush, offset, strength, *nodes[i]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crease_cc
|
||||
|
||||
void do_crease_brush(const Scene &scene, const Sculpt &sd, Object &object, Span<PBVHNode *> nodes)
|
||||
{
|
||||
do_crease_or_blob_brush(scene, sd, false, object, nodes);
|
||||
}
|
||||
|
||||
void do_blob_brush(const Scene &scene, const Sculpt &sd, Object &object, Span<PBVHNode *> nodes)
|
||||
{
|
||||
do_crease_or_blob_brush(scene, sd, true, object, nodes);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
struct Scene;
|
||||
struct Sculpt;
|
||||
struct Object;
|
||||
struct PBVHNode;
|
||||
@@ -13,6 +14,8 @@ struct PBVHNode;
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
void do_clay_strips_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_crease_brush(const Scene &scene, const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_blob_brush(const Scene &scene, const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_displacement_eraser_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
/** A simple normal-direction displacement. */
|
||||
void do_draw_brush(const Sculpt &sd, Object &object, Span<PBVHNode *> nodes);
|
||||
|
||||
@@ -45,6 +45,7 @@ struct Cache;
|
||||
};
|
||||
|
||||
void scale_translations(MutableSpan<float3> translations, Span<float> factors);
|
||||
void scale_translations(MutableSpan<float3> translations, float factor);
|
||||
void scale_factors(MutableSpan<float> factors, float strength);
|
||||
|
||||
/**
|
||||
|
||||
@@ -3485,7 +3485,8 @@ namespace blender::ed::sculpt_paint {
|
||||
/* NOTE: we do the topology update before any brush actions to avoid
|
||||
* issues with the proxies. The size of the proxy can't change, so
|
||||
* topology must be updated first. */
|
||||
static void sculpt_topology_update(const Sculpt &sd,
|
||||
static void sculpt_topology_update(const Scene & /*scene*/,
|
||||
const Sculpt &sd,
|
||||
Object &ob,
|
||||
const Brush &brush,
|
||||
UnifiedPaintSettings & /*ups*/,
|
||||
@@ -3578,7 +3579,8 @@ static void push_undo_nodes(Object &ob, const Brush &brush, PBVHNode *node)
|
||||
}
|
||||
}
|
||||
|
||||
static void do_brush_action(const Sculpt &sd,
|
||||
static void do_brush_action(const Scene &scene,
|
||||
const Sculpt &sd,
|
||||
Object &ob,
|
||||
const Brush &brush,
|
||||
UnifiedPaintSettings &ups,
|
||||
@@ -3747,10 +3749,10 @@ static void do_brush_action(const Sculpt &sd,
|
||||
}
|
||||
break;
|
||||
case SCULPT_TOOL_CREASE:
|
||||
SCULPT_do_crease_brush(sd, ob, nodes);
|
||||
do_crease_brush(scene, sd, ob, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_BLOB:
|
||||
SCULPT_do_crease_brush(sd, ob, nodes);
|
||||
do_blob_brush(scene, sd, ob, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_PINCH:
|
||||
SCULPT_do_pinch_brush(sd, ob, nodes);
|
||||
@@ -4134,13 +4136,15 @@ void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache &ca
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
using BrushActionFunc = void (*)(const Sculpt &sd,
|
||||
using BrushActionFunc = void (*)(const Scene &scene,
|
||||
const Sculpt &sd,
|
||||
Object &ob,
|
||||
const Brush &brush,
|
||||
UnifiedPaintSettings &ups,
|
||||
PaintModeSettings &paint_mode_settings);
|
||||
|
||||
static void do_tiled(const Sculpt &sd,
|
||||
static void do_tiled(const Scene &scene,
|
||||
const Sculpt &sd,
|
||||
Object &ob,
|
||||
const Brush &brush,
|
||||
UnifiedPaintSettings &ups,
|
||||
@@ -4179,7 +4183,7 @@ static void do_tiled(const Sculpt &sd,
|
||||
|
||||
/* First do the "un-tiled" position to initialize the stroke for this location. */
|
||||
cache->tile_pass = 0;
|
||||
action(sd, ob, brush, ups, paint_mode_settings);
|
||||
action(scene, sd, ob, brush, ups, paint_mode_settings);
|
||||
|
||||
/* Now do it for all the tiles. */
|
||||
copy_v3_v3_int(cur, start);
|
||||
@@ -4198,13 +4202,14 @@ static void do_tiled(const Sculpt &sd,
|
||||
cache->plane_offset[dim] = cur[dim] * step[dim];
|
||||
cache->initial_location[dim] = cur[dim] * step[dim] + original_initial_location[dim];
|
||||
}
|
||||
action(sd, ob, brush, ups, paint_mode_settings);
|
||||
action(scene, sd, ob, brush, ups, paint_mode_settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_radial_symmetry(const Sculpt &sd,
|
||||
static void do_radial_symmetry(const Scene &scene,
|
||||
const Sculpt &sd,
|
||||
Object &ob,
|
||||
const Brush &brush,
|
||||
UnifiedPaintSettings &ups,
|
||||
@@ -4220,7 +4225,7 @@ static void do_radial_symmetry(const Sculpt &sd,
|
||||
const float angle = 2.0f * M_PI * i / sd.radial_symm[axis - 'X'];
|
||||
ss.cache->radial_symmetry_pass = i;
|
||||
SCULPT_cache_calc_brushdata_symm(*ss.cache, symm, axis, angle);
|
||||
do_tiled(sd, ob, brush, ups, paint_mode_settings, action);
|
||||
do_tiled(scene, sd, ob, brush, ups, paint_mode_settings, action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4239,7 +4244,8 @@ static void sculpt_fix_noise_tear(const Sculpt &sd, Object &ob)
|
||||
}
|
||||
}
|
||||
|
||||
static void do_symmetrical_brush_actions(const Sculpt &sd,
|
||||
static void do_symmetrical_brush_actions(const Scene &scene,
|
||||
const Sculpt &sd,
|
||||
Object &ob,
|
||||
const BrushActionFunc action,
|
||||
UnifiedPaintSettings &ups,
|
||||
@@ -4266,11 +4272,11 @@ static void do_symmetrical_brush_actions(const Sculpt &sd,
|
||||
cache.radial_symmetry_pass = 0;
|
||||
|
||||
SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
|
||||
do_tiled(sd, ob, brush, ups, paint_mode_settings, action);
|
||||
do_tiled(scene, sd, ob, brush, ups, paint_mode_settings, action);
|
||||
|
||||
do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'X', feather);
|
||||
do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'Y', feather);
|
||||
do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'Z', feather);
|
||||
do_radial_symmetry(scene, sd, ob, brush, ups, paint_mode_settings, action, symm, 'X', feather);
|
||||
do_radial_symmetry(scene, sd, ob, brush, ups, paint_mode_settings, action, symm, 'Y', feather);
|
||||
do_radial_symmetry(scene, sd, ob, brush, ups, paint_mode_settings, action, symm, 'Z', feather);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5800,6 +5806,7 @@ static void sculpt_stroke_update_step(bContext *C,
|
||||
PointerRNA *itemptr)
|
||||
{
|
||||
UnifiedPaintSettings &ups = CTX_data_tool_settings(C)->unified_paint_settings;
|
||||
const Scene &scene = *CTX_data_scene(C);
|
||||
Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
|
||||
Object &ob = *CTX_data_active_object(C);
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
@@ -5828,10 +5835,11 @@ static void sculpt_stroke_update_step(bContext *C,
|
||||
}
|
||||
|
||||
if (dyntopo::stroke_is_dyntopo(ss, brush)) {
|
||||
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups, tool_settings.paint_mode);
|
||||
do_symmetrical_brush_actions(
|
||||
scene, sd, ob, sculpt_topology_update, ups, tool_settings.paint_mode);
|
||||
}
|
||||
|
||||
do_symmetrical_brush_actions(sd, ob, do_brush_action, ups, tool_settings.paint_mode);
|
||||
do_symmetrical_brush_actions(scene, sd, ob, do_brush_action, ups, tool_settings.paint_mode);
|
||||
sculpt_combine_proxies(sd, ob);
|
||||
|
||||
/* Hack to fix noise texture tearing mesh. */
|
||||
@@ -5851,8 +5859,10 @@ static void sculpt_stroke_update_step(bContext *C,
|
||||
*/
|
||||
if (!(ELEM(brush.sculpt_tool,
|
||||
SCULPT_TOOL_DRAW,
|
||||
SCULPT_TOOL_CLAY_STRIPS,
|
||||
SCULPT_TOOL_SCRAPE,
|
||||
SCULPT_TOOL_BLOB,
|
||||
SCULPT_TOOL_CREASE,
|
||||
SCULPT_TOOL_CLAY_STRIPS,
|
||||
SCULPT_TOOL_FILL) &&
|
||||
BKE_pbvh_type(*ss.pbvh) == PBVH_FACES))
|
||||
{
|
||||
@@ -6543,7 +6553,7 @@ void calc_front_face(const float3 &view_normal,
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
const float dot = math::dot(view_normal, vert_normals[verts[i]]);
|
||||
factors[i] *= dot > 0.0f ? dot : 0.0f;
|
||||
factors[i] *= std::max(dot, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6791,6 +6801,13 @@ void scale_translations(const MutableSpan<float3> translations, const Span<float
|
||||
}
|
||||
}
|
||||
|
||||
void scale_translations(const MutableSpan<float3> translations, const float factor)
|
||||
{
|
||||
for (const int i : translations.index_range()) {
|
||||
translations[i] *= factor;
|
||||
}
|
||||
}
|
||||
|
||||
void scale_factors(const MutableSpan<float> factors, const float strength)
|
||||
{
|
||||
if (strength == 1.0f) {
|
||||
|
||||
@@ -829,117 +829,6 @@ void SCULPT_do_layer_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sculpt Crease & Blob Brush
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
|
||||
*/
|
||||
static void do_crease_brush_task(Object &ob,
|
||||
const Brush &brush,
|
||||
SculptProjectVector *spvc,
|
||||
const float flippedbstrength,
|
||||
const float *offset,
|
||||
PBVHNode *node)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
|
||||
PBVHVertexIter vd;
|
||||
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);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (*ss.pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
if (!sculpt_brush_test_sq_fn(test, vd.co)) {
|
||||
continue;
|
||||
}
|
||||
/* Offset vertex. */
|
||||
auto_mask::node_update(automask_data, vd);
|
||||
|
||||
const float fade = SCULPT_brush_strength_factor(ss,
|
||||
brush,
|
||||
vd.co,
|
||||
sqrtf(test.dist),
|
||||
vd.no,
|
||||
vd.fno,
|
||||
vd.mask,
|
||||
vd.vertex,
|
||||
thread_id,
|
||||
&automask_data);
|
||||
float val1[3];
|
||||
float val2[3];
|
||||
|
||||
/* First we pinch. */
|
||||
sub_v3_v3v3(val1, test.location, vd.co);
|
||||
if (brush.falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
|
||||
project_plane_v3_v3v3(val1, val1, ss.cache->view_normal);
|
||||
}
|
||||
|
||||
mul_v3_fl(val1, fade * flippedbstrength);
|
||||
|
||||
sculpt_project_v3(spvc, val1, val1);
|
||||
|
||||
/* Then we draw. */
|
||||
mul_v3_v3fl(val2, offset, fade);
|
||||
|
||||
add_v3_v3v3(proxy[vd.i], val1, val2);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
void SCULPT_do_crease_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes)
|
||||
{
|
||||
using namespace blender;
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
const Scene *scene = ss.cache->vc->scene;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
|
||||
float offset[3];
|
||||
float bstrength = ss.cache->bstrength;
|
||||
float flippedbstrength, crease_correction;
|
||||
float brush_alpha;
|
||||
|
||||
SculptProjectVector spvc;
|
||||
|
||||
/* Offset with as much as possible factored in already. */
|
||||
mul_v3_v3fl(offset, ss.cache->sculpt_normal_symm, ss.cache->radius);
|
||||
mul_v3_v3(offset, ss.cache->scale);
|
||||
mul_v3_fl(offset, bstrength);
|
||||
|
||||
/* We divide out the squared alpha and multiply by the squared crease
|
||||
* to give us the pinch strength. */
|
||||
crease_correction = brush.crease_pinch_factor * brush.crease_pinch_factor;
|
||||
brush_alpha = BKE_brush_alpha_get(scene, &brush);
|
||||
if (brush_alpha > 0.0f) {
|
||||
crease_correction /= brush_alpha * brush_alpha;
|
||||
}
|
||||
|
||||
/* We always want crease to pinch or blob to relax even when draw is negative. */
|
||||
flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
|
||||
crease_correction * bstrength;
|
||||
|
||||
if (brush.sculpt_tool == SCULPT_TOOL_BLOB) {
|
||||
flippedbstrength *= -1.0f;
|
||||
}
|
||||
|
||||
/* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
|
||||
* point. Without this we get a 'flat' surface surrounding the pinch. */
|
||||
sculpt_project_v3_cache_init(&spvc, ss.cache->sculpt_normal_symm);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
do_crease_brush_task(ob, brush, &spvc, flippedbstrength, offset, nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void do_pinch_brush_task(Object &ob,
|
||||
const Brush &brush,
|
||||
const float (*stroke_xz)[3],
|
||||
|
||||
@@ -2049,7 +2049,6 @@ void SCULPT_do_snake_hook_brush(const Sculpt &sd, Object &ob, blender::Span<PBVH
|
||||
void SCULPT_do_thumb_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_rotate_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_layer_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_crease_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_pinch_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_grab_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_elastic_deform_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
|
||||
Reference in New Issue
Block a user