Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py1
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh26
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc38
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc97
-rw-r--r--source/blender/geometry/intern/resample_curves.cc40
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c7
8 files changed, 140 insertions, 72 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 122c7078c04..7bac7343bca 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -523,6 +523,7 @@ class _draw_tool_settings_context_mode:
layout.prop(brush.curves_sculpt_settings, "curve_length")
layout.prop(brush.curves_sculpt_settings, "interpolate_length")
layout.prop(brush.curves_sculpt_settings, "interpolate_shape")
+ layout.prop(brush.curves_sculpt_settings, "interpolate_point_count")
if brush.curves_sculpt_tool == 'GROW_SHRINK':
layout.prop(brush, "direction", expand=True, text="")
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
new file mode 100644
index 00000000000..62b060093e9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BKE_curves.hh"
+
+/** \file
+ * \ingroup bke
+ * \brief Low-level operations for curves.
+ */
+
+namespace blender::bke::curves {
+
+/**
+ * Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
+ */
+void fill_curve_counts(const bke::CurvesGeometry &curves,
+ Span<IndexRange> curve_ranges,
+ MutableSpan<int> counts);
+
+/**
+ * Turn an array of sizes into the offset at each index including all previous sizes.
+ */
+void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
+
+} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c9e88362b80..0b4f81df452 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -117,6 +117,7 @@ set(SRC
intern/curveprofile.cc
intern/curves.cc
intern/curves_geometry.cc
+ intern/curves_utils.cc
intern/customdata.cc
intern/customdata_file.c
intern/data_transfer.c
@@ -356,6 +357,7 @@ set(SRC
BKE_curveprofile.h
BKE_curves.h
BKE_curves.hh
+ BKE_curves_utils.hh
BKE_customdata.h
BKE_customdata_file.h
BKE_data_transfer.h
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
new file mode 100644
index 00000000000..78c2382b62f
--- /dev/null
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_curves_utils.hh"
+
+namespace blender::bke::curves {
+
+void fill_curve_counts(const bke::CurvesGeometry &curves,
+ const Span<IndexRange> curve_ranges,
+ MutableSpan<int> counts)
+{
+ threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
+ for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
+ threading::parallel_for(curves_range, 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ counts[i] = curves.points_for_curve(i).size();
+ }
+ });
+ }
+ });
+}
+
+void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int start_offset)
+{
+ int offset = start_offset;
+ for (const int i : counts_to_offsets.index_range().drop_back(1)) {
+ const int count = counts_to_offsets[i];
+ BLI_assert(count > 0);
+ counts_to_offsets[i] = offset;
+ offset += count;
+ }
+ counts_to_offsets.last() = offset;
+}
+
+} // namespace blender::bke::curves
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 6edc9194319..18bdbb88d8f 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -18,6 +18,7 @@
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
@@ -105,10 +106,11 @@ struct AddOperationExecutor {
bool use_front_face_;
bool interpolate_length_;
bool interpolate_shape_;
+ bool interpolate_point_count_;
bool use_interpolation_;
float new_curve_length_;
int add_amount_;
- int points_per_curve_;
+ int constant_points_per_curve_;
/** Various matrices to convert between coordinate spaces. */
float4x4 curves_to_world_mat_;
@@ -129,6 +131,15 @@ struct AddOperationExecutor {
Vector<int> looptri_indices;
};
+ struct NeighborInfo {
+ /* Curve index of the neighbor. */
+ int index;
+ /* The weights of all neighbors of a new curve add up to 1. */
+ float weight;
+ };
+ static constexpr int max_neighbors = 5;
+ using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+
void execute(AddOperation &self, bContext *C, const StrokeExtension &stroke_extension)
{
self_ = &self;
@@ -172,10 +183,12 @@ struct AddOperationExecutor {
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
- points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
+ constant_points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
- use_interpolation_ = interpolate_length_ || interpolate_shape_;
+ interpolate_point_count_ = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_;
new_curve_length_ = brush_settings_->curve_length;
tot_old_curves_ = curves_->curves_num();
@@ -215,18 +228,26 @@ struct AddOperationExecutor {
return;
}
+ Array<NeighborsVector> neighbors_per_curve;
if (use_interpolation_) {
this->ensure_curve_roots_kdtree();
+ neighbors_per_curve = this->find_curve_neighbors(added_points);
}
+ /* Resize to add the new curves, building the offests in the array owned by thge curves. */
const int tot_added_curves = added_points.bary_coords.size();
- const int tot_added_points = tot_added_curves * points_per_curve_;
+ curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves);
+ if (interpolate_point_count_) {
+ this->initialize_curve_offsets_with_interpolation(neighbors_per_curve);
+ }
+ else {
+ this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_);
+ }
- curves_->resize(curves_->points_num() + tot_added_points,
- curves_->curves_num() + tot_added_curves);
+ /* Resize to add the correct point count calculated as part of building the offsets. */
+ curves_->resize(curves_->offsets().last(), curves_->curves_num());
- threading::parallel_invoke([&]() { this->initialize_curve_offsets(tot_added_curves); },
- [&]() { this->initialize_attributes(added_points); });
+ this->initialize_attributes(added_points, neighbors_per_curve);
curves_->update_curve_types();
@@ -580,33 +601,37 @@ struct AddOperationExecutor {
}
}
- void initialize_curve_offsets(const int tot_added_curves)
+ void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve)
{
- MutableSpan<int> offsets = curves_->offsets_for_write();
- threading::parallel_for(IndexRange(tot_added_curves), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int curve_i = tot_old_curves_ + i;
- offsets[curve_i + 1] = tot_old_points_ + (i + 1) * points_per_curve_;
+ MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
+
+ attribute_math::DefaultMixer<int> mixer{new_offsets};
+ threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) {
+ for (const int i : curves_range) {
+ for (const NeighborInfo &neighbor : neighbors_per_curve[i]) {
+ const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size();
+ mixer.mix_in(i, neighbor_points_num, neighbor.weight);
+ }
}
});
- }
+ mixer.finalize();
- struct NeighborInfo {
- /* Curve index of the neighbor. */
- int index;
- /* The weights of all neighbors of a new curve add up to 1. */
- float weight;
- };
- static constexpr int max_neighbors = 5;
- using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+ bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_);
+ }
- void initialize_attributes(const AddedPoints &added_points)
+ void initialize_curve_offsets_without_interpolation(const int points_per_curve)
{
- Array<NeighborsVector> neighbors_per_curve;
- if (use_interpolation_) {
- neighbors_per_curve = this->find_curve_neighbors(added_points);
+ MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
+ int offset = tot_old_points_;
+ for (const int i : new_offsets.index_range()) {
+ new_offsets[i] = offset;
+ offset += points_per_curve;
}
+ }
+ void initialize_attributes(const AddedPoints &added_points,
+ const Span<NeighborsVector> neighbors_per_curve)
+ {
Array<float> new_lengths_cu(added_points.bary_coords.size());
if (interpolate_length_) {
this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
@@ -735,15 +760,14 @@ struct AddOperationExecutor {
threading::parallel_for(
added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
for (const int i : range) {
- const int first_point_i = tot_old_points_ + i * points_per_curve_;
+ const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
const float3 &root_cu = added_points.positions_cu[i];
const float length = lengths_cu[i];
const float3 &normal_su = normals_su[i];
const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
const float3 tip_cu = root_cu + length * normal_cu;
- initialize_straight_curve_positions(
- root_cu, tip_cu, positions_cu.slice(first_point_i, points_per_curve_));
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
}
});
}
@@ -764,23 +788,22 @@ struct AddOperationExecutor {
added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
for (const int i : range) {
const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
+ const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
const float length_cu = new_lengths_cu[i];
const float3 &normal_su = new_normals_su[i];
const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
const float3 &root_cu = added_points.positions_cu[i];
- const int first_point_i = tot_old_points_ + i * points_per_curve_;
if (neighbors.is_empty()) {
/* If there are no neighbors, just make a straight line. */
const float3 tip_cu = root_cu + length_cu * normal_cu;
- initialize_straight_curve_positions(
- root_cu, tip_cu, positions_cu.slice(first_point_i, points_per_curve_));
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
continue;
}
- positions_cu.slice(first_point_i, points_per_curve_).fill(root_cu);
+ positions_cu.slice(points).fill(root_cu);
for (const NeighborInfo &neighbor : neighbors) {
const int neighbor_curve_i = neighbor.index;
@@ -814,8 +837,8 @@ struct AddOperationExecutor {
const float neighbor_length_cu = neighbor_spline.length();
const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
- const float resample_factor = (1.0f / (points_per_curve_ - 1.0f)) * length_factor;
- for (const int j : IndexRange(points_per_curve_)) {
+ const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
+ for (const int j : IndexRange(points.size())) {
const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
j * resample_factor);
const float index_factor = lookup.evaluated_index + lookup.factor;
@@ -825,7 +848,7 @@ struct AddOperationExecutor {
const float3 relative_coord = p - neighbor_root_cu;
float3 rotated_relative_coord = relative_coord;
mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
- positions_cu[first_point_i + j] += neighbor.weight * rotated_relative_coord;
+ positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
}
}
}
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
index 5eba3ff3b3a..7895225a189 100644
--- a/source/blender/geometry/intern/resample_curves.cc
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -8,6 +8,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
#include "BKE_geometry_fields.hh"
#include "GEO_resample_curves.hh"
@@ -196,37 +197,6 @@ static void copy_between_curves(const bke::CurvesGeometry &src_curves,
});
}
-/**
- * Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
- */
-static void fill_curve_counts(const bke::CurvesGeometry &src_curves,
- const Span<IndexRange> curve_ranges,
- MutableSpan<int> counts)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
- for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
- for (const int i : curves_range) {
- counts[i] = src_curves.points_for_curve(i).size();
- }
- }
- });
-}
-
-/**
- * Turn an array of sizes into the offset at each index including all previous sizes.
- */
-static void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets)
-{
- int total = 0;
- for (const int i : counts_to_offsets.index_range().drop_back(1)) {
- const int count = counts_to_offsets[i];
- BLI_assert(count > 0);
- counts_to_offsets[i] = total;
- total += count;
- }
- counts_to_offsets.last() = total;
-}
-
static Curves *resample_to_uniform(const CurveComponent &src_component,
const fn::Field<bool> &selection_field,
const fn::Field<int> &count_field)
@@ -257,8 +227,8 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
src_curves.curves_range(), nullptr);
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
- fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
- accumulate_counts_to_offsets(dst_offsets);
+ bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
/* All resampled curves are poly curves. */
@@ -428,8 +398,8 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
dst_offsets[i] = src_curves.evaluated_points_for_curve(i).size();
}
});
- fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
- accumulate_counts_to_offsets(dst_offsets);
+ bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 1d5f1351de0..f409d1c0442 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -618,6 +618,7 @@ typedef enum eBrushCurvesSculptFlag {
BRUSH_CURVES_SCULPT_FLAG_GROW_SHRINK_INVERT = (1 << 1),
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH = (1 << 2),
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE = (1 << 3),
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT = (1 << 4),
} eBrushCurvesSculptFlag;
#define MAX_BRUSH_PIXEL_RADIUS 500
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index f7edba24dea..9161fee2584 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1975,6 +1975,13 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Interpolate Length", "Use length of the curves in close proximity");
+ prop = RNA_def_property(srna, "interpolate_point_count", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT);
+ RNA_def_property_ui_text(prop,
+ "Interpolate Point Count",
+ "Use the number of points from the curves in close proximity");
+
prop = RNA_def_property(srna, "interpolate_shape", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE);
RNA_def_property_ui_text(