46 KDTree_3d *original_curve_roots_kdtree_ =
nullptr;
48 KDTree_3d *deformed_curve_roots_kdtree_ =
nullptr;
51 int original_curve_num_ = 0;
58 if (original_curve_roots_kdtree_ !=
nullptr) {
59 BLI_kdtree_3d_free(original_curve_roots_kdtree_);
61 if (deformed_curve_roots_kdtree_ !=
nullptr) {
62 BLI_kdtree_3d_free(deformed_curve_roots_kdtree_);
186 const int already_added_curves =
self_->new_deformed_root_positions_.size();
187 KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves +
188 new_positions_cu.
size());
195 512 < already_added_curves + new_positions_cu.
size(),
198 for (const int i : IndexRange(already_added_curves)) {
199 BLI_kdtree_3d_insert(new_roots_kdtree, -1, self_->new_deformed_root_positions_[i]);
201 for (
const int new_i : new_positions_cu.
index_range()) {
202 const float3 &root_pos_cu = new_positions_cu[new_i];
203 BLI_kdtree_3d_insert(new_roots_kdtree, new_i, root_pos_cu);
205 BLI_kdtree_3d_balance(new_roots_kdtree);
211 new_positions_cu.index_range(), 128, [&](
const IndexRange range) {
212 for (const int new_i : range) {
213 const float3 &new_root_pos_cu = new_positions_cu[new_i];
214 KDTreeNearest_3d nearest;
215 nearest.dist = FLT_MAX;
216 BLI_kdtree_3d_find_nearest(
217 self_->deformed_curve_roots_kdtree_, new_root_pos_cu, &nearest);
218 if (nearest.dist < brush_settings_->minimum_distance) {
219 new_curve_skipped[new_i] = true;
226 for (
const int new_i : new_positions_cu.index_range()) {
227 if (new_curve_skipped[new_i]) {
230 const float3 &root_pos_cu = new_positions_cu[new_i];
231 BLI_kdtree_3d_range_search_cb_cpp(
235 [&](
const int other_new_i,
const float * ,
float ) {
236 if (other_new_i == -1) {
237 new_curve_skipped[new_i] = true;
240 if (new_i == other_new_i) {
243 new_curve_skipped[other_new_i] =
true;
249 for (
int64_t i = new_positions_cu.size() - 1; i >= 0; i--) {
250 if (new_curve_skipped[i]) {
251 new_positions_cu.remove_and_reorder(i);
252 new_uvs.remove_and_reorder(i);
255 self_->new_deformed_root_positions_.extend(new_positions_cu);
257 const Span<float3> corner_normals_su = surface_orig_->corner_normals();
258 const Span<int3> surface_corner_tris_orig = surface_orig_->corner_tris();
259 const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_corner_tris_orig};
261 geometry::AddCurvesOnMeshInputs add_inputs;
262 add_inputs.uvs = new_uvs;
263 add_inputs.interpolate_length = brush_settings_->
flag &
265 add_inputs.interpolate_radius = brush_settings_->
flag &
267 add_inputs.interpolate_shape = brush_settings_->
flag &
269 add_inputs.interpolate_point_count = brush_settings_->
flag &
271 add_inputs.interpolate_resolution = curves_orig_->
attributes().
contains(
"resolution");
272 add_inputs.fallback_curve_length = brush_settings_->
curve_length;
273 add_inputs.fallback_curve_radius = brush_settings_->
curve_radius;
274 add_inputs.fallback_point_count = std::max(2, brush_settings_->
points_per_curve);
275 add_inputs.transforms = &transforms_;
276 add_inputs.surface = surface_orig_;
277 add_inputs.corner_normals_su = corner_normals_su;
278 add_inputs.surface_corner_tris = surface_corner_tris_orig;
279 add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
280 add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_;
282 const geometry::AddCurvesOnMeshOutputs add_outputs = geometry::add_curves_on_mesh(
283 *curves_orig_, add_inputs);
285 if (bke::GSpanAttributeWriter selection = attributes.lookup_for_write_span(
".selection")) {
286 curves::fill_selection_true(selection.span.slice(selection.domain == bke::AttrDomain::Point ?
287 add_outputs.new_points_range :
288 add_outputs.new_curves_range));
292 if (add_outputs.uv_error) {
304 bke::crazyspace::get_evaluated_curves_deformation(*ctx_.
depsgraph, *curves_ob_orig_);
307 const Span<float3> deformed_positions = deformation.positions;
310 auto roots_kdtree_from_positions = [&](
const Span<float3> positions) {
311 KDTree_3d *kdtree = BLI_kdtree_3d_new(curves_orig_->
curves_num());
312 for (
const int curve_i : curves_orig_->
curves_range()) {
313 const int root_point_i = curve_offsets[curve_i];
314 BLI_kdtree_3d_insert(kdtree, curve_i, positions[root_point_i]);
316 BLI_kdtree_3d_balance(kdtree);
320 threading::parallel_invoke(
321 1024 < original_positions.
size() + deformed_positions.
size(),
323 self_->original_curve_roots_kdtree_ = roots_kdtree_from_positions(original_positions);
326 self_->deformed_curve_roots_kdtree_ = roots_kdtree_from_positions(deformed_positions);
338 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
345 const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
366 for (
int i = new_points - 1; i >= 0; i--) {
367 const float3 pos_su = positions_su[i];
371 const float dist_to_brush_re =
math::distance(brush_pos_re_, pos_re);
373 brush_, dist_to_brush_re, brush_radius_re_);
374 const float weight = brush_strength_ * radius_falloff;
383 const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
384 bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
387 r_positions_su.
extend(positions_su);
402 if (!brush_3d.has_value()) {
408 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
414 const float brush_radius_sq_su =
pow2f(brush_radius_su);
417 BLI_bvhtree_range_query_cpp(
418 *surface_bvh_eval_.
tree,
421 [&](
const int index,
const float3 & ,
const float ) {
422 selected_corner_tri_indices.append(index);
425 const float brush_plane_area_su =
M_PI * brush_radius_sq_su;
432 const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
435 selected_corner_tri_indices,
438 approximate_density_su,
444 for (
int i = new_points - 1; i >= 0; i--) {
445 const float3 pos_su = positions_su[i];
447 const float dist_to_brush_cu =
math::distance(pos_cu, brush_pos_cu);
449 brush_, dist_to_brush_cu, brush_3d->radius_cu);
450 const float weight = brush_strength_ * radius_falloff;
459 const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
460 bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
463 r_positions_su.
extend(positions_su);
468void DensityAddOperation::on_stroke_extended(
const bContext &C,
472 executor.
execute(*
this, C, stroke_extension);
535 curves_id_ =
static_cast<Curves *
>(object_->
data);
536 curves_ = &curves_id_->
geometry.wrap();
541 surface_ob_orig_ = curves_id_->
surface;
542 if (surface_ob_orig_ ==
nullptr) {
545 surface_orig_ =
static_cast<Mesh *
>(surface_ob_orig_->
data);
548 if (surface_ob_eval_ ==
nullptr) {
565 curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
572 bke::crazyspace::get_evaluated_curves_deformation(*ctx_.
depsgraph, *object_);
574 const int first_point_i = curves_->
offsets()[curve_i];
575 self_->deformed_root_positions_.append(deformation.positions[first_point_i]);
579 root_points_kdtree_ = BLI_kdtree_3d_new(curve_selection_.
size());
582 const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
583 BLI_kdtree_3d_insert(root_points_kdtree_, curve_i, pos_cu);
585 BLI_kdtree_3d_balance(root_points_kdtree_);
590 this->reduce_density_projected_with_symmetry(curves_to_keep);
593 this->reduce_density_spherical_with_symmetry(curves_to_keep);
600 const IndexMask mask_to_keep = IndexMask::from_bools(curves_to_keep, mask_memory);
605 array_utils::gather(self_->deformed_root_positions_.as_span(),
608 self_->deformed_root_positions_ = std::move(new_deformed_positions);
610 *curves_ = bke::curves_copy_curve_selection(*curves_, mask_to_keep, {});
622 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
623 this->reduce_density_projected(brush_transform, curves_to_keep);
629 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
630 const float brush_radius_sq_re =
pow2f(brush_radius_re);
638 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
640 for (const int curve_i : range) {
641 if (!curves_to_keep[curve_i]) {
642 allow_remove_curve[curve_i] = true;
645 const float3 pos_cu = math::transform_point(brush_transform,
646 self_->deformed_root_positions_[curve_i]);
648 const float2 pos_re = ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, projection);
649 const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
650 if (dist_to_brush_sq_re > brush_radius_sq_re) {
653 const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
654 const float radius_falloff = BKE_brush_curve_strength(
655 brush_, dist_to_brush_re, brush_radius_re);
656 const float weight = brush_strength_ * radius_falloff;
657 if (rng.get_float() < weight) {
658 allow_remove_curve[curve_i] = true;
665 for (
const int curve_i : segment) {
666 if (!curves_to_keep[curve_i]) {
669 if (!allow_remove_curve[curve_i]) {
672 const float3 orig_pos_cu = self_->deformed_root_positions_[curve_i];
676 if (dist_to_brush_sq_re > brush_radius_sq_re) {
679 BLI_kdtree_3d_range_search_cb_cpp(
683 [&](
const int other_curve_i,
const float * ,
float ) {
684 if (other_curve_i == curve_i) {
687 if (allow_remove_curve[other_curve_i]) {
688 curves_to_keep[other_curve_i] =
false;
698 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
706 if (!brush_3d.has_value()) {
712 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
714 this->reduce_density_spherical(brush_pos_cu, brush_3d->radius_cu, curves_to_keep);
719 const float brush_radius_cu,
722 const float brush_radius_sq_cu =
pow2f(brush_radius_cu);
728 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
730 for (const int curve_i : range) {
731 if (!curves_to_keep[curve_i]) {
732 allow_remove_curve[curve_i] = true;
735 const float3 pos_cu = self_->deformed_root_positions_[curve_i];
737 const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu);
738 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
741 const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
742 const float radius_falloff = BKE_brush_curve_strength(
743 brush_, dist_to_brush_cu, brush_radius_cu);
744 const float weight = brush_strength_ * radius_falloff;
745 if (rng.get_float() < weight) {
746 allow_remove_curve[curve_i] = true;
753 for (
const int curve_i : segment) {
754 if (!curves_to_keep[curve_i]) {
757 if (!allow_remove_curve[curve_i]) {
760 const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
762 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
766 BLI_kdtree_3d_range_search_cb_cpp(
770 [&](
const int other_curve_i,
const float * ,
float ) {
771 if (other_curve_i == curve_i) {
774 if (allow_remove_curve[other_curve_i]) {
775 curves_to_keep[other_curve_i] =
false;
784void DensitySubtractOperation::on_stroke_extended(
const bContext &C,
788 executor.
execute(*
this, C, stroke_extension);
818 if (surface_ob_orig ==
nullptr) {
822 if (surface_ob_eval ==
nullptr) {
826 if (curves.curves_num() <= 1) {
830 if (surface_mesh_eval ==
nullptr) {
845 depsgraph, region, v3d, transforms, surface_bvh_eval, brush_pos_re, brush_radius_re);
846 if (!brush_3d.has_value()) {
850 const float3 brush_pos_cu = brush_3d->position_cu;
851 const float brush_radius_cu = brush_3d->radius_cu;
852 const float brush_radius_sq_cu =
pow2f(brush_radius_cu);
855 bke::crazyspace::get_evaluated_curves_deformation(
depsgraph, curves_ob_orig);
856 const Span<int> offsets = curves.offsets();
861 threading::parallel_for(curves.curves_range(), 512, [&](
const IndexRange range) {
862 int &valid_curve_count = valid_curve_count_by_thread.local();
863 for (const int curve_i : range) {
864 const int root_point_i = offsets[curve_i];
865 const float3 &root_pos_cu = deformation.positions[root_point_i];
866 const float dist_sq_cu = math::distance_squared(root_pos_cu, brush_pos_cu);
867 if (dist_sq_cu < brush_radius_sq_cu) {
868 distances_sq_to_brush[curve_i] = {math::distance_squared(root_pos_cu, brush_pos_cu),
873 distances_sq_to_brush[curve_i] = {FLT_MAX, -1};
877 const int valid_curve_count = std::accumulate(
878 valid_curve_count_by_thread.begin(), valid_curve_count_by_thread.end(), 0);
881 const int check_curve_count = std::min<int>(8, valid_curve_count);
882 std::partial_sort(distances_sq_to_brush.begin(),
883 distances_sq_to_brush.begin() + check_curve_count,
884 distances_sq_to_brush.end());
888 float min_dist_sq_cu =
FLT_MAX;
889 for (
const int i :
IndexRange(check_curve_count)) {
890 const float3 &pos_i = deformation.positions[offsets[distances_sq_to_brush[i].second]];
891 for (
int j = i + 1; j < check_curve_count; j++) {
892 const float3 &pos_j = deformation.positions[offsets[distances_sq_to_brush[j].second]];
898 const float min_dist_cu = std::sqrt(min_dist_sq_cu);
899 if (min_dist_cu > brush.curves_sculpt_settings->minimum_distance) {
910 return std::make_unique<DensityAddOperation>();
912 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)
void free_bvhtree_from_mesh(BVHTreeFromMesh *data)
BVHTree * BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data, const Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
@ BVHTREE_FROM_CORNER_TRIS
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)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ 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)
static RandomNumberGenerator from_random_seed()
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(const 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
std::optional< CurvesBrush3D > sample_curves_surface_3d_brush(const Depsgraph &depsgraph, const ARegion ®ion, const View3D &v3d, const CurvesSurfaceTransforms &transforms, const BVHTreeFromMesh &surface_bvh, const float2 &brush_pos_re, const float brush_radius_re)
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 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)
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))
struct BrushCurvesSculptSettings * curves_sculpt_settings
struct ToolSettings * toolsettings
const CurvesSculpt * curves_sculpt_
BVHTreeFromMesh surface_bvh_eval_
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)
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_
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_
BVHTreeFromMesh surface_bvh_eval_
void reduce_density_projected(const float4x4 &brush_transform, MutableSpan< bool > curves_to_keep)
void WM_main_add_notifier(uint type, void *reference)