45 KDTree_3d *original_curve_roots_kdtree_ =
nullptr;
47 KDTree_3d *deformed_curve_roots_kdtree_ =
nullptr;
50 int original_curve_num_ = 0;
57 if (original_curve_roots_kdtree_ !=
nullptr) {
58 BLI_kdtree_3d_free(original_curve_roots_kdtree_);
60 if (deformed_curve_roots_kdtree_ !=
nullptr) {
61 BLI_kdtree_3d_free(deformed_curve_roots_kdtree_);
184 const int already_added_curves =
self_->new_deformed_root_positions_.size();
185 KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves +
186 new_positions_cu.
size());
193 512 < already_added_curves + new_positions_cu.
size(),
196 for (const int i : IndexRange(already_added_curves)) {
197 BLI_kdtree_3d_insert(new_roots_kdtree, -1, self_->new_deformed_root_positions_[i]);
199 for (
const int new_i : new_positions_cu.
index_range()) {
200 const float3 &root_pos_cu = new_positions_cu[new_i];
201 BLI_kdtree_3d_insert(new_roots_kdtree, new_i, root_pos_cu);
203 BLI_kdtree_3d_balance(new_roots_kdtree);
210 for (const int new_i : range) {
211 const float3 &new_root_pos_cu = new_positions_cu[new_i];
212 KDTreeNearest_3d nearest;
213 nearest.dist = FLT_MAX;
214 BLI_kdtree_3d_find_nearest(
215 self_->deformed_curve_roots_kdtree_, new_root_pos_cu, &nearest);
216 if (nearest.dist < brush_settings_->minimum_distance) {
217 new_curve_skipped[new_i] = true;
224 for (
const int new_i : new_positions_cu.index_range()) {
225 if (new_curve_skipped[new_i]) {
228 const float3 &root_pos_cu = new_positions_cu[new_i];
229 BLI_kdtree_3d_range_search_cb_cpp(
233 [&](
const int other_new_i,
const float * ,
float ) {
234 if (other_new_i == -1) {
235 new_curve_skipped[new_i] = true;
238 if (new_i == other_new_i) {
241 new_curve_skipped[other_new_i] =
true;
247 for (
int64_t i = new_positions_cu.size() - 1; i >= 0; i--) {
248 if (new_curve_skipped[i]) {
249 new_positions_cu.remove_and_reorder(i);
250 new_uvs.remove_and_reorder(i);
253 self_->new_deformed_root_positions_.extend(new_positions_cu);
255 const Span<float3> corner_normals_su = surface_orig_->corner_normals();
256 const Span<int3> surface_corner_tris_orig = surface_orig_->corner_tris();
257 const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_corner_tris_orig};
259 geometry::AddCurvesOnMeshInputs add_inputs;
260 add_inputs.uvs = new_uvs;
261 add_inputs.interpolate_length = brush_settings_->
flag &
263 add_inputs.interpolate_radius = brush_settings_->
flag &
265 add_inputs.interpolate_shape = brush_settings_->
flag &
267 add_inputs.interpolate_point_count = brush_settings_->
flag &
269 add_inputs.interpolate_resolution = curves_orig_->
attributes().
contains(
"resolution");
270 add_inputs.fallback_curve_length = brush_settings_->
curve_length;
271 add_inputs.fallback_curve_radius = brush_settings_->
curve_radius;
272 add_inputs.fallback_point_count = std::max(2, brush_settings_->
points_per_curve);
273 add_inputs.transforms = &transforms_;
274 add_inputs.surface = surface_orig_;
275 add_inputs.corner_normals_su = corner_normals_su;
276 add_inputs.surface_corner_tris = surface_corner_tris_orig;
277 add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
278 add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_;
280 const geometry::AddCurvesOnMeshOutputs add_outputs = geometry::add_curves_on_mesh(
281 *curves_orig_, add_inputs);
283 if (bke::GSpanAttributeWriter selection = attributes.lookup_for_write_span(
".selection")) {
284 curves::fill_selection_true(selection.span.slice(selection.domain == bke::AttrDomain::Point ?
285 add_outputs.new_points_range :
286 add_outputs.new_curves_range));
290 if (
const std::optional<Bounds<float3>> center_cu = bounds::min_max(
298 if (add_outputs.uv_error) {
310 bke::crazyspace::get_evaluated_curves_deformation(*ctx_.
depsgraph, *curves_ob_orig_);
316 auto roots_kdtree_from_positions = [&](
const Span<float3> positions) {
317 KDTree_3d *kdtree = BLI_kdtree_3d_new(curves_orig_->
curves_num());
318 for (
const int curve_i : curves_orig_->
curves_range()) {
319 const int root_point_i = curve_offsets[curve_i];
320 BLI_kdtree_3d_insert(kdtree, curve_i, positions[root_point_i]);
322 BLI_kdtree_3d_balance(kdtree);
326 threading::parallel_invoke(
327 1024 < original_positions.
size() + deformed_positions.
size(),
329 self_->original_curve_roots_kdtree_ = roots_kdtree_from_positions(original_positions);
332 self_->deformed_curve_roots_kdtree_ = roots_kdtree_from_positions(deformed_positions);
344 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
351 const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
372 for (
int i = new_points - 1; i >= 0; i--) {
373 const float3 pos_su = positions_su[i];
377 const float dist_to_brush_re =
math::distance(brush_pos_re_, pos_re);
379 brush_, dist_to_brush_re, brush_radius_re_);
380 const float weight = brush_strength_ * radius_falloff;
389 const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
390 bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
393 r_positions_su.
extend(positions_su);
408 if (!brush_3d.has_value()) {
414 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
420 const float brush_radius_sq_su =
pow2f(brush_radius_su);
424 *surface_bvh_eval_.
tree,
427 [&](
const int index,
const float3 & ,
const float ) {
428 selected_corner_tri_indices.append(index);
431 const float brush_plane_area_su =
M_PI * brush_radius_sq_su;
438 const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
441 selected_corner_tri_indices,
444 approximate_density_su,
450 for (
int i = new_points - 1; i >= 0; i--) {
451 const float3 pos_su = positions_su[i];
453 const float dist_to_brush_cu =
math::distance(pos_cu, brush_pos_cu);
455 brush_, dist_to_brush_cu, brush_3d->radius_cu);
456 const float weight = brush_strength_ * radius_falloff;
465 const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
466 bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
469 r_positions_su.
extend(positions_su);
474void DensityAddOperation::on_stroke_extended(
const bContext &C,
478 executor.
execute(*
this, C, stroke_extension);
541 curves_id_ =
static_cast<Curves *
>(object_->
data);
542 curves_ = &curves_id_->
geometry.wrap();
547 surface_ob_orig_ = curves_id_->
surface;
548 if (surface_ob_orig_ ==
nullptr) {
551 surface_orig_ =
static_cast<Mesh *
>(surface_ob_orig_->
data);
554 if (surface_ob_eval_ ==
nullptr) {
559 surface_bvh_eval_ = surface_eval_->bvh_corner_tris();
570 curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
577 bke::crazyspace::get_evaluated_curves_deformation(*ctx_.
depsgraph, *object_);
579 const int first_point_i = curves_->
offsets()[curve_i];
580 self_->deformed_root_positions_.append(deformation.
positions[first_point_i]);
584 root_points_kdtree_ = BLI_kdtree_3d_new(curve_selection_.
size());
587 const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
588 BLI_kdtree_3d_insert(root_points_kdtree_, curve_i, pos_cu);
590 BLI_kdtree_3d_balance(root_points_kdtree_);
595 this->reduce_density_projected_with_symmetry(curves_to_keep);
598 this->reduce_density_spherical_with_symmetry(curves_to_keep);
605 const IndexMask mask_to_keep = IndexMask::from_bools(curves_to_keep, mask_memory);
610 array_utils::gather(self_->deformed_root_positions_.as_span(),
613 self_->deformed_root_positions_ = std::move(new_deformed_positions);
615 *curves_ = bke::curves_copy_curve_selection(*curves_, mask_to_keep, {});
627 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
628 this->reduce_density_projected(brush_transform, curves_to_keep);
634 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
635 const float brush_radius_sq_re =
pow2f(brush_radius_re);
643 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
645 for (const int curve_i : range) {
646 if (!curves_to_keep[curve_i]) {
647 allow_remove_curve[curve_i] = true;
650 const float3 pos_cu = math::transform_point(brush_transform,
651 self_->deformed_root_positions_[curve_i]);
653 const float2 pos_re = ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, projection);
654 const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
655 if (dist_to_brush_sq_re > brush_radius_sq_re) {
658 const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
659 const float radius_falloff = BKE_brush_curve_strength(
660 brush_, dist_to_brush_re, brush_radius_re);
661 const float weight = brush_strength_ * radius_falloff;
662 if (rng.get_float() < weight) {
663 allow_remove_curve[curve_i] = true;
670 for (
const int curve_i : segment) {
671 if (!curves_to_keep[curve_i]) {
674 if (!allow_remove_curve[curve_i]) {
677 const float3 orig_pos_cu = self_->deformed_root_positions_[curve_i];
681 if (dist_to_brush_sq_re > brush_radius_sq_re) {
684 BLI_kdtree_3d_range_search_cb_cpp(
688 [&](
const int other_curve_i,
const float * ,
float ) {
689 if (other_curve_i == curve_i) {
692 if (allow_remove_curve[other_curve_i]) {
693 curves_to_keep[other_curve_i] =
false;
703 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
711 if (!brush_3d.has_value()) {
717 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
719 this->reduce_density_spherical(brush_pos_cu, brush_3d->radius_cu, curves_to_keep);
724 const float brush_radius_cu,
727 const float brush_radius_sq_cu =
pow2f(brush_radius_cu);
733 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
735 for (const int curve_i : range) {
736 if (!curves_to_keep[curve_i]) {
737 allow_remove_curve[curve_i] = true;
740 const float3 pos_cu = self_->deformed_root_positions_[curve_i];
742 const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu);
743 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
746 const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
747 const float radius_falloff = BKE_brush_curve_strength(
748 brush_, dist_to_brush_cu, brush_radius_cu);
749 const float weight = brush_strength_ * radius_falloff;
750 if (rng.get_float() < weight) {
751 allow_remove_curve[curve_i] = true;
758 for (
const int curve_i : segment) {
759 if (!curves_to_keep[curve_i]) {
762 if (!allow_remove_curve[curve_i]) {
765 const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
767 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
771 BLI_kdtree_3d_range_search_cb_cpp(
775 [&](
const int other_curve_i,
const float * ,
float ) {
776 if (other_curve_i == curve_i) {
779 if (allow_remove_curve[other_curve_i]) {
780 curves_to_keep[other_curve_i] =
false;
789void DensitySubtractOperation::on_stroke_extended(
const bContext &C,
793 executor.
execute(*
this, C, stroke_extension);
823 if (surface_ob_orig ==
nullptr) {
827 if (surface_ob_eval ==
nullptr) {
835 if (surface_mesh_eval ==
nullptr) {
848 depsgraph, region, v3d, transforms, surface_bvh_eval, brush_pos_re, brush_radius_re);
849 if (!brush_3d.has_value()) {
853 const float3 brush_pos_cu = brush_3d->position_cu;
854 const float brush_radius_cu = brush_3d->radius_cu;
855 const float brush_radius_sq_cu =
pow2f(brush_radius_cu);
858 bke::crazyspace::get_evaluated_curves_deformation(
depsgraph, curves_ob_orig);
865 int &valid_curve_count = valid_curve_count_by_thread.local();
866 for (const int curve_i : range) {
867 const int root_point_i = offsets[curve_i];
868 const float3 &root_pos_cu = deformation.positions[root_point_i];
869 const float dist_sq_cu = math::distance_squared(root_pos_cu, brush_pos_cu);
870 if (dist_sq_cu < brush_radius_sq_cu) {
871 distances_sq_to_brush[curve_i] = {math::distance_squared(root_pos_cu, brush_pos_cu),
876 distances_sq_to_brush[curve_i] = {FLT_MAX, -1};
880 const int valid_curve_count = std::accumulate(
881 valid_curve_count_by_thread.begin(), valid_curve_count_by_thread.end(), 0);
884 const int check_curve_count = std::min<int>(8, valid_curve_count);
885 std::partial_sort(distances_sq_to_brush.begin(),
886 distances_sq_to_brush.begin() + check_curve_count,
887 distances_sq_to_brush.end());
891 float min_dist_sq_cu =
FLT_MAX;
892 for (
const int i :
IndexRange(check_curve_count)) {
893 const float3 &pos_i = deformation.positions[offsets[distances_sq_to_brush[i].second]];
894 for (
int j = i + 1; j < check_curve_count; j++) {
895 const float3 &pos_j = deformation.positions[offsets[distances_sq_to_brush[j].second]];
901 const float min_dist_cu = std::sqrt(min_dist_sq_cu);
902 if (min_dist_cu > brush.curves_sculpt_settings->minimum_distance) {
913 return std::make_unique<DensityAddOperation>();
915 return std::make_unique<DensitySubtractOperation>();
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Depsgraph * CTX_data_depsgraph_on_load(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
#define BLI_assert_unreachable()
A KD-tree for nearest neighbor search.
MINLINE float pow2f(float x)
#define BLI_SCOPED_DEFER(function_to_defer)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_RADIUS
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE
eBrushCurvesSculptDensityMode
@ BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE
@ BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD
void ED_region_tag_redraw(ARegion *region)
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
bool ED_view3d_win_to_segment_clipped(const Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], bool do_clip_planes)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static RandomNumberGenerator from_random_seed()
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr bool is_empty() const
void remove_and_reorder(const int64_t index)
void append(const T &value)
IndexRange index_range() const
MutableSpan< T > as_mutable_span()
void extend(Span< T > array)
bool contains(StringRef attribute_id) const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
Span< int > offsets() const
Span< float3 > positions() const
AttributeAccessor attributes() const
const Depsgraph * depsgraph
~DensityAddOperation() override
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
const Depsgraph * depsgraph
void report_invalid_uv_map(ReportList *reports)
void report_empty_evaluated_surface(ReportList *reports)
float brush_radius_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
void remember_stroke_position(Scene &scene, const float3 &brush_position_wo)
void report_missing_uv_map_on_original_surface(ReportList *reports)
static bool use_add_density_mode(const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
void report_missing_uv_map_on_evaluated_surface(ReportList *reports)
void report_missing_surface(ReportList *reports)
std::optional< CurvesBrush3D > sample_curves_surface_3d_brush(const Depsgraph &depsgraph, const ARegion ®ion, const View3D &v3d, const CurvesSurfaceTransforms &transforms, const bke::BVHTreeFromMesh &surface_bvh, const float2 &brush_pos_re, const float brush_radius_re)
void report_empty_original_surface(ReportList *reports)
float brush_strength_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
Vector< float4x4 > get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
std::unique_ptr< CurvesSculptStrokeOperation > new_density_operation(const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
float transform_brush_radius(const float4x4 &transform, const float3 &brush_position, const float old_radius)
T distance(const T &a, const T &b)
void min_inplace(T &a, const T &b)
CartesianBasis invert(const CartesianBasis &basis)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_invoke(Functions &&...functions)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
void BLI_bvhtree_range_query_cpp(const BVHTree &tree, const float3 co, float radius, BVHTree_RangeQuery_CPP fn)
struct BrushCurvesSculptSettings * curves_sculpt_settings
struct ToolSettings * toolsettings
const CurvesSculpt * curves_sculpt_
Object * surface_ob_orig_
VArraySpan< float2 > surface_uv_map_eval_
const Mesh * surface_orig_
Object * surface_ob_eval_
void sample_projected_with_symmetry(RandomNumberGenerator &rng, Vector< float2 > &r_uvs, Vector< float3 > &r_positions_su)
Span< int3 > surface_corner_tris_eval_
DensityAddOperation * self_
CurvesSurfaceTransforms transforms_
void sample_spherical_with_symmetry(RandomNumberGenerator &rng, Vector< float2 > &r_uvs, Vector< float3 > &r_positions_su)
CurvesSculptCommonContext ctx_
const BrushCurvesSculptSettings * brush_settings_
DensityAddOperationExecutor(const bContext &C)
bke::BVHTreeFromMesh surface_bvh_eval_
CurvesGeometry * curves_orig_
void execute(DensityAddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void prepare_curve_roots_kdtrees()
void reduce_density_spherical_with_symmetry(MutableSpan< bool > curves_to_keep)
void execute(DensitySubtractOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
float brush_radius_factor_
IndexMaskMemory selected_curve_memory_
bke::BVHTreeFromMesh surface_bvh_eval_
float brush_radius_base_re_
CurvesSculptCommonContext ctx_
IndexMask curve_selection_
CurvesSurfaceTransforms transforms_
void reduce_density_spherical(const float3 &brush_pos_cu, const float brush_radius_cu, MutableSpan< bool > curves_to_keep)
void reduce_density_projected_with_symmetry(MutableSpan< bool > curves_to_keep)
DensitySubtractOperationExecutor(const bContext &C)
KDTree_3d * root_points_kdtree_
void reduce_density_projected(const float4x4 &brush_transform, MutableSpan< bool > curves_to_keep)
void WM_main_add_notifier(uint type, void *reference)