Sculpt: Clay Strips optimizations
This patch introduces some optimizations to Clay Strips, resulting in a speedup of approximately 1.22x. - The translations are calculated more efficiently using the local space, similar to the approach used for the Plane brush. - Plane trimming is computed in local space. - Strength is applied to the offset vector, avoiding an extra per-vertex multiplication. - The local space is constructed such that vertices affected by the brush have a positive z-coordinate. Note: this patch doesn't alter the way the brush works. Any difference should be considered a bug. Pull Request: https://projects.blender.org/blender/blender/pulls/137558
This commit is contained in:
@@ -2,6 +2,19 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edsculpt
|
||||
*
|
||||
* The Clay Strips brush displaces vertices toward the brush plane.
|
||||
* The displacement occurs in the direction of the plane's normal.
|
||||
* Only vertices located below the plane (in brush-local space) are affected.
|
||||
*
|
||||
* The magnitude of the displacement is determined by the product of the following factors:
|
||||
* - A falloff factor based on the XY distance from the center of the plane
|
||||
* - A parabolic falloff factor based on the local Z distance from the plane
|
||||
* - Additional standard modifiers such as masking, brush strength, texture masking, etc.
|
||||
*/
|
||||
|
||||
#include "editors/sculpt_paint/brushes/brushes.hh"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
@@ -33,43 +46,87 @@ inline namespace clay_strips_cc {
|
||||
|
||||
struct LocalData {
|
||||
Vector<float3> positions;
|
||||
Vector<float2> xy_positions;
|
||||
Vector<float> z_positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies a linear falloff based on the z distance in brush local space to the factor.
|
||||
*
|
||||
* Note: We may want to provide users the ability to change this falloff in the future, the
|
||||
* important detail is that we reduce the influence of the brush on vertices that are potentially
|
||||
* "deep" inside the cube test area (i.e. on a nearby plane).
|
||||
*
|
||||
* TODO: Depending on if other brushes begin to use the calc_brush_cube_distances, we may want
|
||||
* to consider either inlining this falloff in that method, or making this a commonly accessible
|
||||
* function.
|
||||
* Transforms positions from object space positions to brush-local space. Splitting the XY and Z
|
||||
* components gives slightly better performance.
|
||||
*/
|
||||
BLI_NOINLINE static void apply_z_axis_falloff(const Span<float3> vert_positions,
|
||||
const Span<int> verts,
|
||||
const float4x4 &mat,
|
||||
const MutableSpan<float> factors)
|
||||
static void calc_local_positions(const Span<float3> vert_positions,
|
||||
const Span<int> verts,
|
||||
const float4x4 &mat,
|
||||
const MutableSpan<float2> xy_positions,
|
||||
const MutableSpan<float> z_positions)
|
||||
{
|
||||
BLI_assert(factors.size() == verts.size());
|
||||
for (const int i : factors.index_range()) {
|
||||
const float local_z_distance = math::abs(
|
||||
math::transform_point(mat, vert_positions[verts[i]]).z);
|
||||
factors[i] *= 1 - local_z_distance;
|
||||
BLI_assert(xy_positions.size() == verts.size());
|
||||
BLI_assert(z_positions.size() == verts.size());
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
const float3 position = math::transform_point(mat, vert_positions[verts[i]]);
|
||||
|
||||
xy_positions[i] = position.xy();
|
||||
z_positions[i] = position.z;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void apply_z_axis_falloff(const Span<float3> positions,
|
||||
const float4x4 &mat,
|
||||
const MutableSpan<float> factors)
|
||||
static void calc_local_positions(const Span<float3> positions,
|
||||
const float4x4 &mat,
|
||||
const MutableSpan<float2> xy_positions,
|
||||
const MutableSpan<float> z_positions)
|
||||
{
|
||||
BLI_assert(factors.size() == positions.size());
|
||||
BLI_assert(xy_positions.size() == positions.size());
|
||||
BLI_assert(z_positions.size() == positions.size());
|
||||
|
||||
for (const int i : positions.index_range()) {
|
||||
const float3 position = math::transform_point(mat, positions[i]);
|
||||
|
||||
xy_positions[i] = position.xy();
|
||||
z_positions[i] = position.z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a parabolic factor of the form `z * (1 - z)` to each vertex.
|
||||
* Vertices outside of the interval (0, 1) are out of range and their factors are set to zero.
|
||||
* Note: The local coordinate system is constructed such that all relevant `z` values
|
||||
* are non-negative.
|
||||
*/
|
||||
static void apply_z_axis_factors(const Span<float> z_positions, const MutableSpan<float> factors)
|
||||
{
|
||||
BLI_assert(factors.size() == z_positions.size());
|
||||
|
||||
for (const int i : factors.index_range()) {
|
||||
const float local_z_distance = math::abs(math::transform_point(mat, positions[i]).z);
|
||||
factors[i] *= 1 - local_z_distance;
|
||||
const float local_z = z_positions[i];
|
||||
|
||||
/* Note: if `local_z > 1`, then `1 - local_z < 0` and the product is negative. */
|
||||
factors[i] *= math::max(0.0f, local_z * (1.0f - local_z));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If plane trim is enabled, vertices with `z` values greater than the
|
||||
* specified `plane_trim` threshold are ignored (i.e., their factors are set to zero).
|
||||
*/
|
||||
static void apply_plane_trim_factors(const Brush &brush,
|
||||
const Span<float> z_positions,
|
||||
const MutableSpan<float> factors)
|
||||
{
|
||||
BLI_assert(factors.size() == z_positions.size());
|
||||
|
||||
const bool use_plane_trim = brush.flag & BRUSH_PLANE_TRIM;
|
||||
if (!use_plane_trim) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const int i : factors.index_range()) {
|
||||
if (z_positions[i] > brush.plane_trim) {
|
||||
factors[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +134,7 @@ static void calc_faces(const Depsgraph &depsgraph,
|
||||
const Sculpt &sd,
|
||||
const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const float4 &plane,
|
||||
const float strength,
|
||||
const bool flip,
|
||||
const float3 &offset,
|
||||
const Span<float3> vert_normals,
|
||||
const MeshAttributeData &attribute_data,
|
||||
const bke::pbvh::MeshNode &node,
|
||||
@@ -100,10 +155,18 @@ static void calc_faces(const Depsgraph &depsgraph,
|
||||
calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
|
||||
}
|
||||
|
||||
tls.xy_positions.resize(verts.size());
|
||||
tls.z_positions.resize(verts.size());
|
||||
MutableSpan<float2> xy_positions = tls.xy_positions;
|
||||
MutableSpan<float> z_positions = tls.z_positions;
|
||||
|
||||
calc_local_positions(position_data.eval, verts, mat, xy_positions, z_positions);
|
||||
apply_z_axis_factors(z_positions, factors);
|
||||
apply_plane_trim_factors(brush, z_positions, factors);
|
||||
|
||||
tls.distances.resize(verts.size());
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
calc_brush_cube_distances(brush, mat, position_data.eval, verts, distances, factors);
|
||||
apply_z_axis_falloff(position_data.eval, verts, mat, factors);
|
||||
calc_brush_cube_distances<float2>(brush, xy_positions, distances);
|
||||
filter_distances_with_radius(1.0f, distances, factors);
|
||||
apply_hardness_to_distances(1.0f, cache.hardness, distances);
|
||||
BKE_brush_calc_curve_factors(
|
||||
@@ -113,23 +176,11 @@ static void calc_faces(const Depsgraph &depsgraph,
|
||||
|
||||
calc_brush_texture_factors(ss, brush, position_data.eval, verts, factors);
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
if (flip) {
|
||||
filter_below_plane_factors(position_data.eval, verts, plane, factors);
|
||||
}
|
||||
else {
|
||||
filter_above_plane_factors(position_data.eval, verts, plane, factors);
|
||||
}
|
||||
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translations_to_plane(position_data.eval, verts, plane, translations);
|
||||
filter_plane_trim_limit_factors(brush, cache, translations, factors);
|
||||
scale_translations(translations, factors);
|
||||
translations_from_offset_and_factors(offset, factors, tls.translations);
|
||||
|
||||
clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
|
||||
position_data.deform(translations, verts);
|
||||
clip_and_lock_translations(sd, ss, position_data.eval, verts, tls.translations);
|
||||
position_data.deform(tls.translations, verts);
|
||||
}
|
||||
|
||||
static void calc_grids(const Depsgraph &depsgraph,
|
||||
@@ -137,9 +188,7 @@ static void calc_grids(const Depsgraph &depsgraph,
|
||||
Object &object,
|
||||
const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const float4 &plane,
|
||||
const float strength,
|
||||
const bool flip,
|
||||
const float3 &offset,
|
||||
const bke::pbvh::GridsNode &node,
|
||||
LocalData &tls)
|
||||
{
|
||||
@@ -158,10 +207,18 @@ static void calc_grids(const Depsgraph &depsgraph,
|
||||
calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
|
||||
}
|
||||
|
||||
tls.xy_positions.resize(positions.size());
|
||||
tls.z_positions.resize(positions.size());
|
||||
MutableSpan<float2> xy_positions = tls.xy_positions;
|
||||
MutableSpan<float> z_positions = tls.z_positions;
|
||||
|
||||
calc_local_positions(positions, mat, xy_positions, z_positions);
|
||||
apply_z_axis_factors(z_positions, factors);
|
||||
apply_plane_trim_factors(brush, z_positions, factors);
|
||||
|
||||
tls.distances.resize(positions.size());
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
calc_brush_cube_distances(brush, mat, positions, distances, factors);
|
||||
apply_z_axis_falloff(positions, mat, factors);
|
||||
calc_brush_cube_distances<float2>(brush, xy_positions, distances);
|
||||
filter_distances_with_radius(1.0f, distances, factors);
|
||||
apply_hardness_to_distances(1.0f, cache.hardness, distances);
|
||||
BKE_brush_calc_curve_factors(
|
||||
@@ -171,23 +228,11 @@ static void calc_grids(const Depsgraph &depsgraph,
|
||||
|
||||
calc_brush_texture_factors(ss, brush, positions, factors);
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
if (flip) {
|
||||
filter_below_plane_factors(positions, plane, factors);
|
||||
}
|
||||
else {
|
||||
filter_above_plane_factors(positions, plane, factors);
|
||||
}
|
||||
|
||||
tls.translations.resize(positions.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translations_to_plane(positions, plane, translations);
|
||||
filter_plane_trim_limit_factors(brush, cache, translations, factors);
|
||||
scale_translations(translations, factors);
|
||||
translations_from_offset_and_factors(offset, factors, tls.translations);
|
||||
|
||||
clip_and_lock_translations(sd, ss, positions, translations);
|
||||
apply_translations(translations, grids, subdiv_ccg);
|
||||
clip_and_lock_translations(sd, ss, positions, tls.translations);
|
||||
apply_translations(tls.translations, grids, subdiv_ccg);
|
||||
}
|
||||
|
||||
static void calc_bmesh(const Depsgraph &depsgraph,
|
||||
@@ -195,9 +240,7 @@ static void calc_bmesh(const Depsgraph &depsgraph,
|
||||
Object &object,
|
||||
const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const float4 &plane,
|
||||
const float strength,
|
||||
const bool flip,
|
||||
const float3 &offset,
|
||||
bke::pbvh::BMeshNode &node,
|
||||
LocalData &tls)
|
||||
{
|
||||
@@ -215,10 +258,18 @@ static void calc_bmesh(const Depsgraph &depsgraph,
|
||||
calc_front_face(cache.view_normal_symm, verts, factors);
|
||||
}
|
||||
|
||||
tls.distances.resize(verts.size());
|
||||
tls.xy_positions.resize(positions.size());
|
||||
tls.z_positions.resize(positions.size());
|
||||
MutableSpan<float2> xy_positions = tls.xy_positions;
|
||||
MutableSpan<float> z_positions = tls.z_positions;
|
||||
|
||||
calc_local_positions(positions, mat, xy_positions, z_positions);
|
||||
apply_z_axis_factors(z_positions, factors);
|
||||
apply_plane_trim_factors(brush, z_positions, factors);
|
||||
|
||||
tls.distances.resize(positions.size());
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
calc_brush_cube_distances(brush, mat, positions, distances, factors);
|
||||
apply_z_axis_falloff(positions, mat, factors);
|
||||
calc_brush_cube_distances<float2>(brush, xy_positions, distances);
|
||||
filter_distances_with_radius(1.0f, distances, factors);
|
||||
apply_hardness_to_distances(1.0f, cache.hardness, distances);
|
||||
BKE_brush_calc_curve_factors(
|
||||
@@ -228,23 +279,11 @@ static void calc_bmesh(const Depsgraph &depsgraph,
|
||||
|
||||
calc_brush_texture_factors(ss, brush, positions, factors);
|
||||
|
||||
scale_factors(factors, strength);
|
||||
tls.translations.resize(positions.size());
|
||||
translations_from_offset_and_factors(offset, factors, tls.translations);
|
||||
|
||||
if (flip) {
|
||||
filter_below_plane_factors(positions, plane, factors);
|
||||
}
|
||||
else {
|
||||
filter_above_plane_factors(positions, plane, factors);
|
||||
}
|
||||
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translations_to_plane(positions, plane, translations);
|
||||
filter_plane_trim_limit_factors(brush, cache, translations, factors);
|
||||
scale_translations(translations, factors);
|
||||
|
||||
clip_and_lock_translations(sd, ss, positions, translations);
|
||||
apply_translations(translations, verts);
|
||||
clip_and_lock_translations(sd, ss, positions, tls.translations);
|
||||
apply_translations(tls.translations, verts);
|
||||
}
|
||||
|
||||
} // namespace clay_strips_cc
|
||||
@@ -271,6 +310,13 @@ void do_clay_strips_brush(const Depsgraph &depsgraph,
|
||||
mat.x_axis() = math::cross(plane_normal, ss.cache->grab_delta_symm);
|
||||
mat.y_axis() = math::cross(plane_normal, float3(mat[0]));
|
||||
mat.z_axis() = plane_normal;
|
||||
|
||||
/* Flip the z-axis so that the vertices below the plane have positive z-coordinates. When the
|
||||
* brush is inverted, the affected z-coordinates are already positive. */
|
||||
if (!flip) {
|
||||
mat.z_axis() *= -1.0f;
|
||||
}
|
||||
|
||||
mat.location() = plane_center;
|
||||
mat = math::normalize(mat);
|
||||
|
||||
@@ -280,10 +326,7 @@ void do_clay_strips_brush(const Depsgraph &depsgraph,
|
||||
tmat.y_axis() *= brush.tip_scale_x;
|
||||
mat = math::invert(tmat);
|
||||
|
||||
float4 plane;
|
||||
plane_from_point_normal_v3(plane, plane_center, plane_normal);
|
||||
|
||||
const float strength = std::abs(ss.cache->bstrength);
|
||||
const float3 offset = plane_normal * ss.cache->bstrength * ss.cache->radius;
|
||||
|
||||
threading::EnumerableThreadSpecific<LocalData> all_tls;
|
||||
switch (pbvh.type()) {
|
||||
@@ -299,9 +342,7 @@ void do_clay_strips_brush(const Depsgraph &depsgraph,
|
||||
sd,
|
||||
brush,
|
||||
mat,
|
||||
plane,
|
||||
strength,
|
||||
flip,
|
||||
offset,
|
||||
vert_normals,
|
||||
attribute_data,
|
||||
nodes[i],
|
||||
@@ -318,7 +359,7 @@ void do_clay_strips_brush(const Depsgraph &depsgraph,
|
||||
MutableSpan<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
LocalData &tls = all_tls.local();
|
||||
calc_grids(depsgraph, sd, object, brush, mat, plane, strength, flip, nodes[i], tls);
|
||||
calc_grids(depsgraph, sd, object, brush, mat, offset, nodes[i], tls);
|
||||
bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
|
||||
});
|
||||
break;
|
||||
@@ -327,7 +368,7 @@ void do_clay_strips_brush(const Depsgraph &depsgraph,
|
||||
MutableSpan<bke::pbvh::BMeshNode> nodes = pbvh.nodes<bke::pbvh::BMeshNode>();
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
LocalData &tls = all_tls.local();
|
||||
calc_bmesh(depsgraph, sd, object, brush, mat, plane, strength, flip, nodes[i], tls);
|
||||
calc_bmesh(depsgraph, sd, object, brush, mat, offset, nodes[i], tls);
|
||||
bke::pbvh::update_node_bounds_bmesh(nodes[i]);
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -323,17 +323,10 @@ void filter_distances_with_radius(float radius, Span<float> distances, MutableSp
|
||||
* Calculate distances based on a "square" brush tip falloff and ignore vertices that are too far
|
||||
* away.
|
||||
*/
|
||||
template<typename T>
|
||||
void calc_brush_cube_distances(const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
Span<float3> positions,
|
||||
Span<int> verts,
|
||||
MutableSpan<float> r_distances,
|
||||
MutableSpan<float> factors);
|
||||
void calc_brush_cube_distances(const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
Span<float3> positions,
|
||||
MutableSpan<float> r_distances,
|
||||
MutableSpan<float> factors);
|
||||
const Span<T> positions,
|
||||
const MutableSpan<float> r_distances);
|
||||
|
||||
/**
|
||||
* Scale the distances based on the brush radius and the cached "hardness" setting, which increases
|
||||
|
||||
@@ -7165,77 +7165,32 @@ void filter_distances_with_radius(const float radius,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void calc_brush_cube_distances(const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const Span<float3> positions,
|
||||
const Span<int> verts,
|
||||
const MutableSpan<float> r_distances,
|
||||
const MutableSpan<float> factors)
|
||||
const Span<T> positions,
|
||||
const MutableSpan<float> r_distances)
|
||||
{
|
||||
BLI_assert(verts.size() == factors.size());
|
||||
BLI_assert(verts.size() == r_distances.size());
|
||||
BLI_assert(r_distances.size() == positions.size());
|
||||
|
||||
const float roundness = brush.tip_roundness;
|
||||
const float roundness_rcp = math::safe_rcp(roundness);
|
||||
const float hardness = 1.0f - roundness;
|
||||
for (const int i : verts.index_range()) {
|
||||
if (factors[i] == 0.0f) {
|
||||
r_distances[i] = std::numeric_limits<float>::max();
|
||||
continue;
|
||||
}
|
||||
const float3 local = math::abs(math::transform_point(mat, positions[verts[i]]));
|
||||
|
||||
if (!(local.x <= 1.0f && local.y <= 1.0f && local.z <= 1.0f)) {
|
||||
factors[i] = 0.0f;
|
||||
r_distances[i] = std::numeric_limits<float>::max();
|
||||
continue;
|
||||
}
|
||||
if (std::min(local.x, local.y) > hardness) {
|
||||
/* Corner, distance to the center of the corner circle. */
|
||||
r_distances[i] = math::distance(float2(hardness), float2(local)) / roundness;
|
||||
continue;
|
||||
}
|
||||
if (std::max(local.x, local.y) > hardness) {
|
||||
/* Side, distance to the square XY axis. */
|
||||
r_distances[i] = (std::max(local.x, local.y) - hardness) / roundness;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Inside the square, constant distance. */
|
||||
r_distances[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void calc_brush_cube_distances(const Brush &brush,
|
||||
const float4x4 &mat,
|
||||
const Span<float3> positions,
|
||||
const MutableSpan<float> r_distances,
|
||||
const MutableSpan<float> factors)
|
||||
{
|
||||
BLI_assert(positions.size() == factors.size());
|
||||
BLI_assert(positions.size() == r_distances.size());
|
||||
|
||||
const float roundness = brush.tip_roundness;
|
||||
const float hardness = 1.0f - roundness;
|
||||
for (const int i : positions.index_range()) {
|
||||
if (factors[i] == 0.0f) {
|
||||
r_distances[i] = std::numeric_limits<float>::max();
|
||||
continue;
|
||||
}
|
||||
const float3 local = math::abs(math::transform_point(mat, positions[i]));
|
||||
const T local = math::abs(positions[i]);
|
||||
|
||||
if (!(local.x <= 1.0f && local.y <= 1.0f && local.z <= 1.0f)) {
|
||||
factors[i] = 0.0f;
|
||||
if (math::reduce_max(local) > 1.0f) {
|
||||
r_distances[i] = std::numeric_limits<float>::max();
|
||||
continue;
|
||||
}
|
||||
if (std::min(local.x, local.y) > hardness) {
|
||||
/* Corner, distance to the center of the corner circle. */
|
||||
r_distances[i] = math::distance(float2(hardness), float2(local)) / roundness;
|
||||
r_distances[i] = math::distance(float2(hardness), float2(local)) * roundness_rcp;
|
||||
continue;
|
||||
}
|
||||
if (std::max(local.x, local.y) > hardness) {
|
||||
/* Side, distance to the square XY axis. */
|
||||
r_distances[i] = (std::max(local.x, local.y) - hardness) / roundness;
|
||||
r_distances[i] = (std::max(local.x, local.y) - hardness) * roundness_rcp;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7243,6 +7198,12 @@ void calc_brush_cube_distances(const Brush &brush,
|
||||
r_distances[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
template void calc_brush_cube_distances<float2>(const Brush &brush,
|
||||
const Span<float2> positions,
|
||||
MutableSpan<float> r_distances);
|
||||
template void calc_brush_cube_distances<float3>(const Brush &brush,
|
||||
const Span<float3> positions,
|
||||
MutableSpan<float> r_distances);
|
||||
|
||||
void apply_hardness_to_distances(const float radius,
|
||||
const float hardness,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "BLI_enumerable_thread_specific.hh"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
@@ -40,6 +41,16 @@
|
||||
|
||||
namespace blender::ed::sculpt_paint::color {
|
||||
|
||||
static void calc_local_positions(const float4x4 &mat,
|
||||
const Span<int> verts,
|
||||
const Span<float3> positions,
|
||||
const MutableSpan<float3> local_positions)
|
||||
{
|
||||
for (const int i : verts.index_range()) {
|
||||
local_positions[i] = math::transform_point(mat, positions[verts[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Func> inline void to_static_color_type(const CPPType &type, const Func &func)
|
||||
{
|
||||
if (type.is<ColorGeometry4f>()) {
|
||||
@@ -247,6 +258,7 @@ bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
|
||||
struct ColorPaintLocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float> auto_mask;
|
||||
Vector<float3> positions;
|
||||
Vector<float> distances;
|
||||
Vector<float4> colors;
|
||||
Vector<float4> new_colors;
|
||||
@@ -372,18 +384,23 @@ static void do_paint_brush_task(const Scene &scene,
|
||||
calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
|
||||
}
|
||||
|
||||
float radius;
|
||||
|
||||
tls.distances.resize(verts.size());
|
||||
const MutableSpan<float> distances = tls.distances;
|
||||
if (brush.tip_roundness < 1.0f) {
|
||||
calc_brush_cube_distances(brush, mat, vert_positions, verts, distances, factors);
|
||||
scale_factors(distances, cache.radius);
|
||||
tls.positions.resize(verts.size());
|
||||
calc_local_positions(mat, verts, vert_positions, tls.positions);
|
||||
calc_brush_cube_distances<float3>(brush, tls.positions, distances);
|
||||
radius = 1.0f;
|
||||
}
|
||||
else {
|
||||
calc_brush_distances(
|
||||
ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
|
||||
radius = cache.radius;
|
||||
}
|
||||
filter_distances_with_radius(cache.radius, distances, factors);
|
||||
apply_hardness_to_distances(cache, distances);
|
||||
filter_distances_with_radius(radius, distances, factors);
|
||||
apply_hardness_to_distances(radius, cache.hardness, distances);
|
||||
calc_brush_strength_factors(cache, brush, distances, factors);
|
||||
|
||||
MutableSpan<float> auto_mask;
|
||||
|
||||
Reference in New Issue
Block a user