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]);
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);
209 new_positions_cu.index_range(), 128, [&](
const IndexRange range) {
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(
291 curves_orig_->
positions().slice(add_outputs.new_points_range)))
298 if (add_outputs.uv_error) {
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);
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) {
360 ctx_.depsgraph,
ctx_.region,
ctx_.v3d, pos_re, start_wo, end_wo,
true);
372 for (
int i = new_points - 1;
i >= 0;
i--) {
373 const float3 pos_su = positions_su[
i];
393 r_positions_su.
extend(positions_su);
408 if (!brush_3d.has_value()) {
414 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
419 transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu);
420 const float brush_radius_sq_su =
pow2f(brush_radius_su);
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;
432 const float approximate_density_su =
brush_settings_->density_add_attempts /
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);
469 r_positions_su.
extend(positions_su);
478 executor.
execute(*
this,
C, stroke_extension);
578 for (
const int curve_i :
curves_->curves_range()) {
579 const int first_point_i =
curves_->offsets()[curve_i];
580 self_->deformed_root_positions_.append(deformation.
positions[first_point_i]);
587 const float3 &pos_cu =
self_->deformed_root_positions_[curve_i];
613 self_->deformed_root_positions_ = std::move(new_deformed_positions);
627 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
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;
711 if (!brush_3d.has_value()) {
717 for (
const float4x4 &brush_transform : symmetry_brush_transforms) {
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;
793 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>();
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)
for(;discarded_id_iter !=nullptr;discarded_id_iter=static_cast< ID * >(discarded_id_iter->next))
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)
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))
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
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()
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)