Sculpt: Data oriented refactor for clay thumb brush
Part of #118145.
Since the initial commit (015d5eda88) there has been a logic
mistake in the code for this brush where a variable was unused. The code
has worked for years in that state, so I left it in. The next commit
will clean up the unused code.
This commit is contained in:
@@ -116,6 +116,7 @@ set(SRC
|
||||
|
||||
brushes/clay.cc
|
||||
brushes/clay_strips.cc
|
||||
brushes/clay_thumb.cc
|
||||
brushes/crease.cc
|
||||
brushes/draw_vector_displacement.cc
|
||||
brushes/draw.cc
|
||||
|
||||
366
source/blender/editors/sculpt_paint/brushes/clay_thumb.cc
Normal file
366
source/blender/editors/sculpt_paint/brushes/clay_thumb.cc
Normal file
@@ -0,0 +1,366 @@
|
||||
/* 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_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_array_utils.hh"
|
||||
#include "BLI_enumerable_thread_specific.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#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 clay_thumb_cc {
|
||||
|
||||
struct LocalData {
|
||||
Vector<float3> positions;
|
||||
Vector<float3> local_positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
|
||||
BLI_NOINLINE static void calc_translations(const Span<float3> positions,
|
||||
const Span<float3> local_positions,
|
||||
const float4 &plane,
|
||||
const float4 &plane_tilt,
|
||||
const MutableSpan<float3> translations)
|
||||
{
|
||||
for (const int i : positions.index_range()) {
|
||||
float3 closest;
|
||||
closest_to_plane_normalized_v3(closest, plane, positions[i]);
|
||||
float3 closest_tilt;
|
||||
closest_to_plane_normalized_v3(closest_tilt, plane_tilt, positions[i]);
|
||||
|
||||
const float tilt_mix = local_positions[i].y > 0.0f ? 0.0f : 1.0f;
|
||||
const float3 mixed = math::interpolate(closest, closest_tilt, tilt_mix);
|
||||
/* NOTE: This has always been unused since the initial implementation of the tool. */
|
||||
UNUSED_VARS(mixed);
|
||||
|
||||
translations[i] = closest_tilt - positions[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_faces(const Sculpt &sd,
|
||||
const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const float4 &plane,
|
||||
const float4 &plane_tilt,
|
||||
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.positions.reinitialize(verts.size());
|
||||
MutableSpan<float3> positions = tls.positions;
|
||||
array_utils::gather(positions_eval, verts, positions);
|
||||
|
||||
tls.factors.reinitialize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(mesh, verts, factors);
|
||||
filter_region_clip_factors(ss, positions, 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, eBrushFalloffShape(brush.falloff_shape), distances, factors);
|
||||
apply_hardness_to_distances(cache, distances);
|
||||
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, factors);
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
tls.local_positions.reinitialize(verts.size());
|
||||
MutableSpan<float3> local_positions = tls.local_positions;
|
||||
transform_positions(positions, mat, local_positions);
|
||||
|
||||
tls.translations.reinitialize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translations(positions, local_positions, plane, plane_tilt, translations);
|
||||
|
||||
scale_translations(translations, factors);
|
||||
|
||||
write_translations(sd, object, positions_eval, verts, translations, positions_orig);
|
||||
}
|
||||
|
||||
static void calc_grids(const Sculpt &sd,
|
||||
const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const float4 &plane,
|
||||
const float4 &plane_tilt,
|
||||
const float strength,
|
||||
const PBVHNode &node,
|
||||
Object &object,
|
||||
LocalData &tls)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const StrokeCache &cache = *ss.cache;
|
||||
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
|
||||
const Span<int> grids = bke::pbvh::node_grid_indices(node);
|
||||
const int grid_verts_num = grids.size() * key.grid_area;
|
||||
|
||||
tls.positions.reinitialize(grid_verts_num);
|
||||
MutableSpan<float3> positions = tls.positions;
|
||||
gather_grids_positions(subdiv_ccg, grids, positions);
|
||||
|
||||
tls.factors.reinitialize(grid_verts_num);
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
|
||||
filter_region_clip_factors(ss, positions, factors);
|
||||
if (brush.flag & BRUSH_FRONTFACE) {
|
||||
calc_front_face(cache.view_normal, subdiv_ccg, grids, factors);
|
||||
}
|
||||
|
||||
tls.distances.reinitialize(grid_verts_num);
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
calc_distance_falloff(
|
||||
ss, positions, eBrushFalloffShape(brush.falloff_shape), distances, factors);
|
||||
apply_hardness_to_distances(cache, distances);
|
||||
calc_brush_strength_factors(cache, brush, distances, factors);
|
||||
|
||||
if (cache.automasking) {
|
||||
auto_mask::calc_grids_factors(object, *cache.automasking, node, grids, factors);
|
||||
}
|
||||
|
||||
calc_brush_texture_factors(ss, brush, positions, factors);
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
tls.local_positions.reinitialize(grid_verts_num);
|
||||
MutableSpan<float3> local_positions = tls.local_positions;
|
||||
transform_positions(positions, mat, local_positions);
|
||||
|
||||
tls.translations.reinitialize(grid_verts_num);
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translations(positions, local_positions, plane, plane_tilt, translations);
|
||||
|
||||
scale_translations(translations, factors);
|
||||
|
||||
clip_and_lock_translations(sd, ss, positions, translations);
|
||||
apply_translations(translations, grids, subdiv_ccg);
|
||||
}
|
||||
|
||||
static void calc_bmesh(const Sculpt &sd,
|
||||
const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const float4 &plane,
|
||||
const float4 &plane_tilt,
|
||||
const float strength,
|
||||
Object &object,
|
||||
PBVHNode &node,
|
||||
LocalData &tls)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const StrokeCache &cache = *ss.cache;
|
||||
|
||||
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(&node);
|
||||
|
||||
tls.positions.reinitialize(verts.size());
|
||||
MutableSpan<float3> positions = tls.positions;
|
||||
gather_bmesh_positions(verts, positions);
|
||||
|
||||
tls.factors.reinitialize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(*ss.bm, verts, factors);
|
||||
filter_region_clip_factors(ss, positions, factors);
|
||||
if (brush.flag & BRUSH_FRONTFACE) {
|
||||
calc_front_face(cache.view_normal, verts, factors);
|
||||
}
|
||||
|
||||
tls.distances.reinitialize(verts.size());
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
calc_distance_falloff(
|
||||
ss, positions, eBrushFalloffShape(brush.falloff_shape), distances, factors);
|
||||
apply_hardness_to_distances(cache, distances);
|
||||
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, factors);
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
tls.local_positions.reinitialize(verts.size());
|
||||
MutableSpan<float3> local_positions = tls.local_positions;
|
||||
transform_positions(positions, mat, local_positions);
|
||||
|
||||
tls.translations.reinitialize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translations(positions, local_positions, plane, plane_tilt, translations);
|
||||
|
||||
scale_translations(translations, factors);
|
||||
|
||||
clip_and_lock_translations(sd, ss, positions, translations);
|
||||
apply_translations(translations, verts);
|
||||
}
|
||||
|
||||
} // namespace clay_thumb_cc
|
||||
|
||||
void do_clay_thumb_brush(const Sculpt &sd, Object &object, Span<PBVHNode *> nodes)
|
||||
{
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
|
||||
const float3 &location = ss.cache->location;
|
||||
|
||||
/* Sampled geometry normal and area center. */
|
||||
float3 area_no_sp;
|
||||
float3 area_no;
|
||||
float3 area_co_tmp;
|
||||
|
||||
float4x4 tmat;
|
||||
|
||||
calc_brush_plane(brush, object, nodes, area_no_sp, area_co_tmp);
|
||||
|
||||
if (brush.sculpt_plane != SCULPT_DISP_DIR_AREA || (brush.flag & BRUSH_ORIGINAL_NORMAL)) {
|
||||
area_no = calc_area_normal(brush, object, nodes).value_or(float3(0));
|
||||
}
|
||||
else {
|
||||
area_no = area_no_sp;
|
||||
}
|
||||
|
||||
/* Delay the first daub because grab delta is not setup. */
|
||||
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache)) {
|
||||
ss.cache->clay_thumb_front_angle = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
|
||||
* stroke. */
|
||||
if (SCULPT_stroke_is_main_symmetry_pass(*ss.cache)) {
|
||||
ss.cache->clay_thumb_front_angle += 0.8f;
|
||||
ss.cache->clay_thumb_front_angle = clamp_f(ss.cache->clay_thumb_front_angle, 0.0f, 60.0f);
|
||||
}
|
||||
|
||||
if (math::is_zero(ss.cache->grab_delta_symmetry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize brush local-space matrix. */
|
||||
float4x4 mat = float4x4::identity();
|
||||
mat.x_axis() = math::cross(area_no, ss.cache->grab_delta_symmetry);
|
||||
mat.y_axis() = math::cross(area_no, mat.x_axis());
|
||||
mat.z_axis() = area_no;
|
||||
mat.location() = ss.cache->location;
|
||||
normalize_m4(mat.ptr());
|
||||
|
||||
/* Scale brush local space matrix. */
|
||||
float4x4 scale = math::from_scale<float4x4>(float3(ss.cache->radius));
|
||||
mul_m4_m4m4(tmat.ptr(), mat.ptr(), scale.ptr());
|
||||
invert_m4_m4(mat.ptr(), tmat.ptr());
|
||||
|
||||
float clay_strength = ss.cache->bstrength * clay_thumb_get_stabilized_pressure(*ss.cache);
|
||||
|
||||
float4 plane_tilt;
|
||||
float3 normal_tilt;
|
||||
float4x4 imat;
|
||||
|
||||
invert_m4_m4(imat.ptr(), mat.ptr());
|
||||
rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss.cache->clay_thumb_front_angle));
|
||||
|
||||
/* Plane aligned to the geometry normal (back part of the brush). */
|
||||
float4 plane;
|
||||
plane_from_point_normal_v3(plane, location, area_no_sp);
|
||||
/* Tilted plane (front part of the brush). */
|
||||
plane_from_point_normal_v3(plane_tilt, location, normal_tilt);
|
||||
|
||||
threading::EnumerableThreadSpecific<LocalData> all_tls;
|
||||
switch (BKE_pbvh_type(*object.sculpt->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
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,
|
||||
mat,
|
||||
plane,
|
||||
plane_tilt,
|
||||
clay_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) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
calc_grids(sd, brush, mat, plane, plane_tilt, clay_strength, *nodes[i], object, tls);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
calc_bmesh(sd, brush, mat, plane, plane_tilt, clay_strength, object, *nodes[i], tls);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float clay_thumb_get_stabilized_pressure(const blender::ed::sculpt_paint::StrokeCache &cache)
|
||||
{
|
||||
float final_pressure = 0.0f;
|
||||
for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
|
||||
final_pressure += cache.clay_pressure_stabilizer[i];
|
||||
}
|
||||
return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
@@ -64,17 +64,6 @@ static ScrapeSampleData join_samples(const ScrapeSampleData &a, const ScrapeSamp
|
||||
return joined;
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void transform_positions(const Span<float3> src,
|
||||
const float4x4 &transform,
|
||||
const MutableSpan<float3> dst)
|
||||
{
|
||||
BLI_assert(src.size() == dst.size());
|
||||
|
||||
for (const int i : src.index_range()) {
|
||||
dst[i] = math::transform_point(transform, src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void filter_plane_side_factors(const Span<float3> positions,
|
||||
const Span<float3> local_positions,
|
||||
const std::array<float4, 2> &scrape_planes,
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace blender::ed::sculpt_paint {
|
||||
|
||||
void do_clay_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_clay_strips_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes);
|
||||
void do_clay_thumb_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);
|
||||
|
||||
@@ -54,6 +54,7 @@ void scale_factors(MutableSpan<float> factors, float strength);
|
||||
void translations_from_offset_and_factors(const float3 &offset,
|
||||
Span<float> factors,
|
||||
MutableSpan<float3> r_translations);
|
||||
void transform_positions(Span<float3> src, const float4x4 &transform, MutableSpan<float3> dst);
|
||||
|
||||
/**
|
||||
* Note on the various positions arrays:
|
||||
|
||||
@@ -3846,7 +3846,7 @@ static void do_brush_action(const Scene &scene,
|
||||
do_multiplane_scrape_brush(sd, ob, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_CLAY_THUMB:
|
||||
SCULPT_do_clay_thumb_brush(sd, ob, nodes);
|
||||
do_clay_thumb_brush(sd, ob, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_FILL:
|
||||
if (invert && brush.flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
|
||||
@@ -4768,7 +4768,7 @@ static float sculpt_brush_dynamic_size_get(const Brush &brush,
|
||||
case SCULPT_TOOL_CLAY_STRIPS:
|
||||
return max_ff(initial_size * 0.30f, initial_size * powf(cache.pressure, 1.5f));
|
||||
case SCULPT_TOOL_CLAY_THUMB: {
|
||||
float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache);
|
||||
float clay_stabilized_pressure = clay_thumb_get_stabilized_pressure(cache);
|
||||
return initial_size * clay_stabilized_pressure;
|
||||
}
|
||||
default:
|
||||
@@ -7356,6 +7356,7 @@ void scale_factors(const MutableSpan<float> factors, const float strength)
|
||||
factor *= strength;
|
||||
}
|
||||
}
|
||||
|
||||
void translations_from_offset_and_factors(const float3 &offset,
|
||||
const Span<float> factors,
|
||||
const MutableSpan<float3> r_translations)
|
||||
@@ -7367,6 +7368,17 @@ void translations_from_offset_and_factors(const float3 &offset,
|
||||
}
|
||||
}
|
||||
|
||||
void transform_positions(const Span<float3> src,
|
||||
const float4x4 &transform,
|
||||
const MutableSpan<float3> dst)
|
||||
{
|
||||
BLI_assert(src.size() == dst.size());
|
||||
|
||||
for (const int i : src.index_range()) {
|
||||
dst[i] = math::transform_point(transform, src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
OffsetIndices<int> create_node_vert_offsets(Span<PBVHNode *> nodes, Array<int> &node_data)
|
||||
{
|
||||
node_data.reinitialize(nodes.size() + 1);
|
||||
|
||||
@@ -137,162 +137,6 @@ void sculpt_project_v3_normal_align(const SculptSession &ss,
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sculpt Clay Thumb Brush
|
||||
* \{ */
|
||||
|
||||
static void do_clay_thumb_brush_task(Object &ob,
|
||||
const Brush &brush,
|
||||
float (*mat)[4],
|
||||
const float *area_no_sp,
|
||||
const float *area_co,
|
||||
const float bstrength,
|
||||
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);
|
||||
|
||||
float plane_tilt[4];
|
||||
float normal_tilt[3];
|
||||
float imat[4][4];
|
||||
|
||||
invert_m4_m4(imat, mat);
|
||||
rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss.cache->clay_thumb_front_angle));
|
||||
|
||||
/* Plane aligned to the geometry normal (back part of the brush). */
|
||||
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
|
||||
/* Tilted plane (front part of the brush). */
|
||||
plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
|
||||
|
||||
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;
|
||||
}
|
||||
float local_co[3];
|
||||
mul_v3_m4v3(local_co, mat, vd.co);
|
||||
float intr[3], intr_tilt[3];
|
||||
float val[3];
|
||||
|
||||
closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
|
||||
closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
|
||||
|
||||
/* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
|
||||
* coordinates. */
|
||||
/* We can also control the mix with a curve if it produces noticeable artifacts in the center
|
||||
* of the brush. */
|
||||
const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
|
||||
interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
|
||||
sub_v3_v3v3(val, intr_tilt, vd.co);
|
||||
|
||||
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);
|
||||
|
||||
mul_v3_v3fl(proxy[vd.i], val, fade);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
float SCULPT_clay_thumb_get_stabilized_pressure(
|
||||
const blender::ed::sculpt_paint::StrokeCache &cache)
|
||||
{
|
||||
float final_pressure = 0.0f;
|
||||
for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
|
||||
final_pressure += cache.clay_pressure_stabilizer[i];
|
||||
}
|
||||
return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
|
||||
}
|
||||
|
||||
void SCULPT_do_clay_thumb_brush(const Sculpt &sd, Object &ob, Span<PBVHNode *> nodes)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
|
||||
|
||||
/* Sampled geometry normal and area center. */
|
||||
float3 area_no_sp;
|
||||
float3 area_no;
|
||||
float3 area_co_tmp;
|
||||
|
||||
float mat[4][4];
|
||||
float scale[4][4];
|
||||
float tmat[4][4];
|
||||
|
||||
calc_brush_plane(brush, ob, nodes, area_no_sp, area_co_tmp);
|
||||
|
||||
if (brush.sculpt_plane != SCULPT_DISP_DIR_AREA || (brush.flag & BRUSH_ORIGINAL_NORMAL)) {
|
||||
area_no = calc_area_normal(brush, ob, nodes).value_or(float3(0));
|
||||
}
|
||||
else {
|
||||
area_no = area_no_sp;
|
||||
}
|
||||
|
||||
/* Delay the first daub because grab delta is not setup. */
|
||||
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache)) {
|
||||
ss.cache->clay_thumb_front_angle = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
|
||||
* stroke. */
|
||||
if (SCULPT_stroke_is_main_symmetry_pass(*ss.cache)) {
|
||||
ss.cache->clay_thumb_front_angle += 0.8f;
|
||||
ss.cache->clay_thumb_front_angle = clamp_f(ss.cache->clay_thumb_front_angle, 0.0f, 60.0f);
|
||||
}
|
||||
|
||||
if (is_zero_v3(ss.cache->grab_delta_symmetry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize brush local-space matrix. */
|
||||
cross_v3_v3v3(mat[0], area_no, ss.cache->grab_delta_symmetry);
|
||||
mat[0][3] = 0.0f;
|
||||
cross_v3_v3v3(mat[1], area_no, mat[0]);
|
||||
mat[1][3] = 0.0f;
|
||||
copy_v3_v3(mat[2], area_no);
|
||||
mat[2][3] = 0.0f;
|
||||
copy_v3_v3(mat[3], ss.cache->location);
|
||||
mat[3][3] = 1.0f;
|
||||
normalize_m4(mat);
|
||||
|
||||
/* Scale brush local space matrix. */
|
||||
scale_m4_fl(scale, ss.cache->radius);
|
||||
mul_m4_m4m4(tmat, mat, scale);
|
||||
invert_m4_m4(mat, tmat);
|
||||
|
||||
float clay_strength = ss.cache->bstrength * SCULPT_clay_thumb_get_stabilized_pressure(*ss.cache);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
do_clay_thumb_brush_task(
|
||||
ob, brush, mat, area_no_sp, ss.cache->location, clay_strength, nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
static void do_snake_hook_brush_task(Object &ob,
|
||||
const Brush &brush,
|
||||
SculptProjectVector *spvc,
|
||||
|
||||
@@ -2036,10 +2036,12 @@ void SCULPT_do_paint_brush_image(PaintModeSettings &paint_mode_settings,
|
||||
blender::Span<PBVHNode *> texnodes);
|
||||
bool SCULPT_use_image_paint_brush(PaintModeSettings &settings, Object &ob);
|
||||
|
||||
float SCULPT_clay_thumb_get_stabilized_pressure(
|
||||
const blender::ed::sculpt_paint::StrokeCache &cache);
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
float clay_thumb_get_stabilized_pressure(const blender::ed::sculpt_paint::StrokeCache &cache);
|
||||
|
||||
}
|
||||
|
||||
void SCULPT_do_clay_thumb_brush(const Sculpt &sd, Object &ob, blender::Span<PBVHNode *> nodes);
|
||||
void SCULPT_do_snake_hook_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);
|
||||
|
||||
Reference in New Issue
Block a user