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_);
182 const int already_added_curves =
self_->new_deformed_root_positions_.size();
183 KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves +
184 new_positions_cu.
size());
191 512 < already_added_curves + new_positions_cu.
size(),
194 for (const int i : IndexRange(already_added_curves)) {
195 BLI_kdtree_3d_insert(new_roots_kdtree, -1, self_->new_deformed_root_positions_[i]);
197 for (
const int new_i : new_positions_cu.
index_range()) {
198 const float3 &root_pos_cu = new_positions_cu[new_i];
199 BLI_kdtree_3d_insert(new_roots_kdtree, new_i, root_pos_cu);
201 BLI_kdtree_3d_balance(new_roots_kdtree);
207 new_positions_cu.index_range(), 128, [&](
const IndexRange range) {
208 for (const int new_i : range) {
209 const float3 &new_root_pos_cu = new_positions_cu[new_i];
210 KDTreeNearest_3d nearest;
211 nearest.dist = FLT_MAX;
212 BLI_kdtree_3d_find_nearest(
213 self_->deformed_curve_roots_kdtree_, new_root_pos_cu, &nearest);
214 if (nearest.dist < brush_settings_->minimum_distance) {
215 new_curve_skipped[new_i] = true;
222 for (
const int new_i : new_positions_cu.index_range()) {
223 if (new_curve_skipped[new_i]) {
226 const float3 &root_pos_cu = new_positions_cu[new_i];
227 BLI_kdtree_3d_range_search_cb_cpp(
231 [&](
const int other_new_i,
const float * ,
float ) {
232 if (other_new_i == -1) {
233 new_curve_skipped[new_i] = true;
236 if (new_i == other_new_i) {
239 new_curve_skipped[other_new_i] =
true;
245 for (
int64_t i = new_positions_cu.size() - 1;
i >= 0;
i--) {
246 if (new_curve_skipped[
i]) {
247 new_positions_cu.remove_and_reorder(
i);
248 new_uvs.remove_and_reorder(
i);
251 self_->new_deformed_root_positions_.extend(new_positions_cu);
253 const Span<float3> corner_normals_su = surface_orig_->corner_normals();
254 const Span<int3> surface_corner_tris_orig = surface_orig_->corner_tris();
255 const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_corner_tris_orig};
257 geometry::AddCurvesOnMeshInputs add_inputs;
258 add_inputs.uvs = new_uvs;
259 add_inputs.interpolate_length = brush_settings_->
flag &
261 add_inputs.interpolate_radius = brush_settings_->
flag &
263 add_inputs.interpolate_shape = brush_settings_->
flag &
265 add_inputs.interpolate_point_count = brush_settings_->
flag &
267 add_inputs.interpolate_resolution = curves_orig_->
attributes().
contains(
"resolution");
268 add_inputs.fallback_curve_length = brush_settings_->
curve_length;
269 add_inputs.fallback_curve_radius = brush_settings_->
curve_radius;
270 add_inputs.fallback_point_count = std::max(2, brush_settings_->
points_per_curve);
271 add_inputs.transforms = &transforms_;
272 add_inputs.surface = surface_orig_;
273 add_inputs.corner_normals_su = corner_normals_su;
274 add_inputs.surface_corner_tris = surface_corner_tris_orig;
275 add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
276 add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_;
278 const geometry::AddCurvesOnMeshOutputs add_outputs = geometry::add_curves_on_mesh(
279 *curves_orig_, add_inputs);
281 if (bke::GSpanAttributeWriter selection = attributes.lookup_for_write_span(
".selection")) {
282 curves::fill_selection_true(selection.span.slice(selection.domain == bke::AttrDomain::Point ?
283 add_outputs.new_points_range :
284 add_outputs.new_curves_range));
288 if (
const std::optional<
Bounds<float3>> center_cu = bounds::min_max(
289 curves_orig_->
positions().slice(add_outputs.new_points_range)))
297 if (add_outputs.uv_error) {
315 auto roots_kdtree_from_positions = [&](
const Span<float3> positions) {
316 KDTree_3d *kdtree = BLI_kdtree_3d_new(
curves_orig_->curves_num());
317 for (
const int curve_i :
curves_orig_->curves_range()) {
318 const int root_point_i = curve_offsets[curve_i];
319 BLI_kdtree_3d_insert(kdtree, curve_i, positions[root_point_i]);
321 BLI_kdtree_3d_balance(kdtree);
326 1024 < original_positions.
size() + deformed_positions.
size(),
328 self_->original_curve_roots_kdtree_ = roots_kdtree_from_positions(original_positions);
331 self_->deformed_curve_roots_kdtree_ = roots_kdtree_from_positions(deformed_positions);
343 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
359 ctx_.depsgraph,
ctx_.region,
ctx_.v3d, pos_re, start_wo, end_wo,
true);
371 for (
int i = new_points - 1;
i >= 0;
i--) {
372 const float3 pos_su = positions_su[
i];
392 r_positions_su.
extend(positions_su);
407 if (!brush_3d.has_value()) {
413 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
418 transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu);
419 const float brush_radius_sq_su =
pow2f(brush_radius_su);
426 [&](
const int index,
const float3 & ,
const float ) {
427 selected_corner_tri_indices.append(index);
430 const float brush_plane_area_su =
M_PI * brush_radius_sq_su;
431 const float approximate_density_su =
brush_settings_->density_add_attempts /
440 selected_corner_tri_indices,
443 approximate_density_su,
449 for (
int i = new_points - 1;
i >= 0;
i--) {
450 const float3 pos_su = positions_su[
i];
452 const float dist_to_brush_cu =
math::distance(pos_cu, brush_pos_cu);
454 brush_, dist_to_brush_cu, brush_3d->radius_cu);
468 r_positions_su.
extend(positions_su);
477 executor.
execute(*
this,
C, stroke_extension);
577 for (
const int curve_i :
curves_->curves_range()) {
578 const int first_point_i =
curves_->offsets()[curve_i];
579 self_->deformed_root_positions_.append(deformation.
positions[first_point_i]);
586 const float3 &pos_cu =
self_->deformed_root_positions_[curve_i];
612 self_->deformed_root_positions_ = std::move(new_deformed_positions);
626 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
634 const float brush_radius_sq_re =
pow2f(brush_radius_re);
642 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
644 for (const int curve_i : range) {
645 if (!curves_to_keep[curve_i]) {
646 allow_remove_curve[curve_i] = true;
649 const float3 pos_cu = math::transform_point(brush_transform,
650 self_->deformed_root_positions_[curve_i]);
652 const float2 pos_re = ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, projection);
653 const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
654 if (dist_to_brush_sq_re > brush_radius_sq_re) {
657 const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
658 const float radius_falloff = BKE_brush_curve_strength(
659 brush_, dist_to_brush_re, brush_radius_re);
660 const float weight = brush_strength_ * radius_falloff;
661 if (rng.get_float() < weight) {
662 allow_remove_curve[curve_i] = true;
669 for (
const int curve_i : segment) {
670 if (!curves_to_keep[curve_i]) {
673 if (!allow_remove_curve[curve_i]) {
676 const float3 orig_pos_cu = self_->deformed_root_positions_[curve_i];
680 if (dist_to_brush_sq_re > brush_radius_sq_re) {
683 BLI_kdtree_3d_range_search_cb_cpp(
687 [&](
const int other_curve_i,
const float * ,
float ) {
688 if (other_curve_i == curve_i) {
691 if (allow_remove_curve[other_curve_i]) {
692 curves_to_keep[other_curve_i] =
false;
710 if (!brush_3d.has_value()) {
716 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
723 const float brush_radius_cu,
726 const float brush_radius_sq_cu =
pow2f(brush_radius_cu);
732 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
734 for (const int curve_i : range) {
735 if (!curves_to_keep[curve_i]) {
736 allow_remove_curve[curve_i] = true;
739 const float3 pos_cu = self_->deformed_root_positions_[curve_i];
741 const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu);
742 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
745 const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
746 const float radius_falloff = BKE_brush_curve_strength(
747 brush_, dist_to_brush_cu, brush_radius_cu);
748 const float weight = brush_strength_ * radius_falloff;
749 if (rng.get_float() < weight) {
750 allow_remove_curve[curve_i] = true;
757 for (
const int curve_i : segment) {
758 if (!curves_to_keep[curve_i]) {
761 if (!allow_remove_curve[curve_i]) {
764 const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
766 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
770 BLI_kdtree_3d_range_search_cb_cpp(
774 [&](
const int other_curve_i,
const float * ,
float ) {
775 if (other_curve_i == curve_i) {
778 if (allow_remove_curve[other_curve_i]) {
779 curves_to_keep[other_curve_i] =
false;
792 executor.
execute(*
this,
C, stroke_extension);
823 if (surface_ob_orig ==
nullptr) {
827 if (surface_ob_eval ==
nullptr) {
831 if (
curves.curves_num() <= 1) {
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);
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>();
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
float BKE_brush_radius_get(const Paint *paint, const Brush *brush)
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)
BPy_StructRNA * depsgraph
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
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(StringRef attribute_id) const
MutableAttributeAccessor attributes_for_write()
Span< float3 > positions() const
AttributeAccessor attributes() const
friend struct DensityAddOperationExecutor
~DensityAddOperation() override
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
friend struct DensitySubtractOperationExecutor
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
void foreach_segment(Fn &&fn) const
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig)
int sample_surface_points_projected(RandomNumberGenerator &rng, const Mesh &mesh, bke::BVHTreeFromMesh &mesh_bvhtree, const float2 &sample_pos_re, float sample_radius_re, FunctionRef< void(const float2 &pos_re, float3 &r_start, float3 &r_end)> region_position_to_ray, bool front_face_only, int tries_num, int max_points, Vector< float3 > &r_bary_coords, Vector< int > &r_tri_indices, Vector< float3 > &r_positions)
int sample_surface_points_spherical(RandomNumberGenerator &rng, const Mesh &mesh, Span< int > tris_to_sample, const float3 &sample_pos, float sample_radius, float approximate_density, Vector< float3 > &r_bary_coords, Vector< int > &r_tri_indices, Vector< float3 > &r_positions)
T sample_corner_attribute_with_bary_coords(const float3 &bary_weights, const int3 &corner_tri, const Span< T > corner_attribute)
CurvesGeometry curves_copy_curve_selection(const CurvesGeometry &curves, const IndexMask &curves_to_copy, const AttributeFilter &attribute_filter)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
void report_invalid_uv_map(ReportList *reports)
float brush_strength_get(const Paint &paint, const Brush &brush, const StrokeExtension &stroke_extension)
void report_empty_evaluated_surface(ReportList *reports)
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 remember_stroke_position(CurvesSculpt &curves_sculpt, const float3 &brush_position_wo)
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)
float brush_radius_get(const Paint &paint, const Brush &brush, const StrokeExtension &stroke_extension)
void report_empty_original_surface(ReportList *reports)
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)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
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))
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
void BLI_bvhtree_range_query_cpp(const BVHTree &tree, const float3 co, float radius, BVHTree_RangeQuery_CPP fn)
VecBase< float, 3 > float3
struct BrushCurvesSculptSettings * curves_sculpt_settings
struct ToolSettings * toolsettings
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()
const CurvesSculpt * curves_sculpt_
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_
Object * surface_ob_orig_
Object * surface_ob_eval_
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_
DensitySubtractOperation * self_
void reduce_density_projected(const float4x4 &brush_transform, MutableSpan< bool > curves_to_keep)
void WM_main_add_notifier(uint type, void *reference)