From 1f94b56d774440d08eb92f2a7a47b9a6a7aa7b84 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 22 Jul 2022 15:39:41 +0200 Subject: Curves: support sculpting on deformed curves Previously, curves sculpt tools only worked on original data. This was very limiting, because one could effectively only sculpt the curves when all procedural effects were turned off. This patch adds support for curves sculpting while looking the result of procedural effects (like deformation based on the surface mesh). This functionality is also known as "crazy space" support in Blender. For more details see D15407. Differential Revision: https://developer.blender.org/D15407 --- .../editors/sculpt_paint/curves_sculpt_density.cc | 408 ++++++++++++--------- 1 file changed, 244 insertions(+), 164 deletions(-) (limited to 'source/blender/editors/sculpt_paint/curves_sculpt_density.cc') diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc index e211a568705..b07f5c74055 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc @@ -2,6 +2,7 @@ #include +#include "BKE_attribute_math.hh" #include "BKE_brush.h" #include "BKE_bvhutils.h" #include "BKE_context.h" @@ -9,11 +10,15 @@ #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_report.h" #include "ED_screen.h" #include "ED_view3d.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "BLI_index_mask_ops.hh" #include "BLI_kdtree.h" @@ -36,7 +41,11 @@ namespace blender::ed::sculpt_paint { class DensityAddOperation : public CurvesSculptStrokeOperation { private: /** Used when some data should be interpolated from existing curves. */ - KDTree_3d *curve_roots_kdtree_ = nullptr; + KDTree_3d *original_curve_roots_kdtree_ = nullptr; + /** Contains curve roots of all curves that existed before the brush started. */ + KDTree_3d *deformed_curve_roots_kdtree_ = nullptr; + /** Root positions of curves that have been added in the current brush stroke. */ + Vector new_deformed_root_positions_; int original_curve_num_ = 0; friend struct DensityAddOperationExecutor; @@ -44,8 +53,11 @@ class DensityAddOperation : public CurvesSculptStrokeOperation { public: ~DensityAddOperation() override { - if (curve_roots_kdtree_ != nullptr) { - BLI_kdtree_3d_free(curve_roots_kdtree_); + if (original_curve_roots_kdtree_ != nullptr) { + BLI_kdtree_3d_free(original_curve_roots_kdtree_); + } + if (deformed_curve_roots_kdtree_ != nullptr) { + BLI_kdtree_3d_free(deformed_curve_roots_kdtree_); } } @@ -56,14 +68,18 @@ struct DensityAddOperationExecutor { DensityAddOperation *self_ = nullptr; CurvesSculptCommonContext ctx_; - Object *object_ = nullptr; - Curves *curves_id_ = nullptr; - CurvesGeometry *curves_ = nullptr; + Object *curves_ob_orig_ = nullptr; + Curves *curves_id_orig_ = nullptr; + CurvesGeometry *curves_orig_ = nullptr; + + Object *surface_ob_orig_ = nullptr; + Mesh *surface_orig_ = nullptr; - Object *surface_ob_ = nullptr; - Mesh *surface_ = nullptr; - Span surface_looptris_; - Span corner_normals_su_; + Object *surface_ob_eval_ = nullptr; + Mesh *surface_eval_ = nullptr; + Span surface_looptris_eval_; + VArraySpan surface_uv_map_eval_; + BVHTreeFromMesh surface_bvh_eval_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -75,8 +91,6 @@ struct DensityAddOperationExecutor { CurvesSurfaceTransforms transforms_; - BVHTreeFromMesh surface_bvh_; - DensityAddOperationExecutor(const bContext &C) : ctx_(C) { } @@ -86,32 +100,51 @@ struct DensityAddOperationExecutor { const StrokeExtension &stroke_extension) { self_ = &self; - object_ = CTX_data_active_object(&C); - curves_id_ = static_cast(object_->data); - curves_ = &CurvesGeometry::wrap(curves_id_->geometry); + curves_ob_orig_ = CTX_data_active_object(&C); + curves_id_orig_ = static_cast(curves_ob_orig_->data); + curves_orig_ = &CurvesGeometry::wrap(curves_id_orig_->geometry); if (stroke_extension.is_first) { - self_->original_curve_num_ = curves_->curves_num(); + self_->original_curve_num_ = curves_orig_->curves_num(); } - if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) { + if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) { + report_missing_surface(stroke_extension.reports); return; } - surface_ob_ = curves_id_->surface; - surface_ = static_cast(surface_ob_->data); - - surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_), - BKE_mesh_runtime_looptri_len(surface_)}; + surface_ob_orig_ = curves_id_orig_->surface; + surface_orig_ = static_cast(surface_ob_orig_->data); - transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface); + surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_); + if (surface_ob_eval_ == nullptr) { + return; + } + surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_); - if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { - BKE_mesh_calc_normals_split(surface_); + BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2); + BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); }); + surface_looptris_eval_ = {BKE_mesh_runtime_looptri_ensure(surface_eval_), + BKE_mesh_runtime_looptri_len(surface_eval_)}; + /* Find UV map. */ + VArraySpan surface_uv_map; + if (curves_id_orig_->surface_uv_map != nullptr) { + surface_uv_map = bke::mesh_attributes(*surface_orig_) + .lookup(curves_id_orig_->surface_uv_map, ATTR_DOMAIN_CORNER); + surface_uv_map_eval_ = bke::mesh_attributes(*surface_eval_) + .lookup(curves_id_orig_->surface_uv_map, + ATTR_DOMAIN_CORNER); + } + if (surface_uv_map.is_empty()) { + report_missing_uv_map_on_original_surface(stroke_extension.reports); + return; + } + if (surface_uv_map_eval_.is_empty()) { + report_missing_uv_map_on_evaluated_surface(stroke_extension.reports); + return; } - corner_normals_su_ = { - reinterpret_cast(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), - surface_->totloop}; + + transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface); curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); @@ -123,23 +156,17 @@ struct DensityAddOperationExecutor { const eBrushFalloffShape falloff_shape = static_cast( brush_->falloff_shape); - BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); - BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); }); - - Vector new_bary_coords; - Vector new_looptri_indices; Vector new_positions_cu; + Vector new_uvs; const double time = PIL_check_seconds_timer() * 1000000.0; RandomNumberGenerator rng{*(uint32_t *)(&time)}; /* Find potential new curve root points. */ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - this->sample_projected_with_symmetry( - rng, new_bary_coords, new_looptri_indices, new_positions_cu); + this->sample_projected_with_symmetry(rng, new_uvs, new_positions_cu); } else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { - this->sample_spherical_with_symmetry( - rng, new_bary_coords, new_looptri_indices, new_positions_cu); + this->sample_spherical_with_symmetry(rng, new_uvs, new_positions_cu); } else { BLI_assert_unreachable(); @@ -148,9 +175,11 @@ struct DensityAddOperationExecutor { pos = transforms_.surface_to_curves * pos; } - this->ensure_curve_roots_kdtree(); + if (stroke_extension.is_first) { + this->prepare_curve_roots_kdtrees(); + } - const int already_added_curves = curves_->curves_num() - self_->original_curve_num_; + const int already_added_curves = self_->new_deformed_root_positions_.size(); KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves + new_positions_cu.size()); BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(new_roots_kdtree); }); @@ -161,15 +190,12 @@ struct DensityAddOperationExecutor { threading::parallel_invoke( /* Build kdtree from root points created by the current stroke. */ [&]() { - const Span positions_cu = curves_->positions(); - for (const int curve_i : curves_->curves_range().take_back(already_added_curves)) { - const float3 &root_pos_cu = positions_cu[curves_->offsets()[curve_i]]; - BLI_kdtree_3d_insert(new_roots_kdtree, curve_i, root_pos_cu); + for (const int i : IndexRange(already_added_curves)) { + BLI_kdtree_3d_insert(new_roots_kdtree, -1, self_->new_deformed_root_positions_[i]); } for (const int new_i : new_positions_cu.index_range()) { - const int index_in_kdtree = curves_->curves_num() + new_i; const float3 &root_pos_cu = new_positions_cu[new_i]; - BLI_kdtree_3d_insert(new_roots_kdtree, index_in_kdtree, root_pos_cu); + BLI_kdtree_3d_insert(new_roots_kdtree, new_i, root_pos_cu); } BLI_kdtree_3d_balance(new_roots_kdtree); }, @@ -183,7 +209,7 @@ struct DensityAddOperationExecutor { KDTreeNearest_3d nearest; nearest.dist = FLT_MAX; BLI_kdtree_3d_find_nearest( - self_->curve_roots_kdtree_, new_root_pos_cu, &nearest); + self_->deformed_curve_roots_kdtree_, new_root_pos_cu, &nearest); if (nearest.dist < brush_settings_->minimum_distance) { new_curve_skipped[new_i] = true; } @@ -201,12 +227,11 @@ struct DensityAddOperationExecutor { new_roots_kdtree, root_pos_cu, brush_settings_->minimum_distance, - [&](const int other_i, const float *UNUSED(co), float UNUSED(dist_sq)) { - if (other_i < curves_->curves_num()) { + [&](const int other_new_i, const float *UNUSED(co), float UNUSED(dist_sq)) { + if (other_new_i == -1) { new_curve_skipped[new_i] = true; return false; } - const int other_new_i = other_i - curves_->curves_num(); if (new_i == other_new_i) { return true; } @@ -219,31 +244,25 @@ struct DensityAddOperationExecutor { for (int64_t i = new_positions_cu.size() - 1; i >= 0; i--) { if (new_curve_skipped[i]) { new_positions_cu.remove_and_reorder(i); - new_bary_coords.remove_and_reorder(i); - new_looptri_indices.remove_and_reorder(i); + new_uvs.remove_and_reorder(i); } } - - /* Find UV map. */ - VArraySpan surface_uv_map; - if (curves_id_->surface_uv_map != nullptr) { - bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_); - surface_uv_map = surface_attributes.lookup(curves_id_->surface_uv_map, - ATTR_DOMAIN_CORNER); - } + self_->new_deformed_root_positions_.extend(new_positions_cu); /* Find normals. */ - if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { - BKE_mesh_calc_normals_split(surface_); + if (!CustomData_has_layer(&surface_orig_->ldata, CD_NORMAL)) { + BKE_mesh_calc_normals_split(surface_orig_); } const Span corner_normals_su = { - reinterpret_cast(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), - surface_->totloop}; + reinterpret_cast(CustomData_get_layer(&surface_orig_->ldata, CD_NORMAL)), + surface_orig_->totloop}; + + const Span surface_looptris_orig = {BKE_mesh_runtime_looptri_ensure(surface_orig_), + BKE_mesh_runtime_looptri_len(surface_orig_)}; + const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig}; geometry::AddCurvesOnMeshInputs add_inputs; - add_inputs.root_positions_cu = new_positions_cu; - add_inputs.bary_coords = new_bary_coords; - add_inputs.looptri_indices = new_looptri_indices; + add_inputs.uvs = new_uvs; add_inputs.interpolate_length = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH; add_inputs.interpolate_shape = brush_settings_->flag & @@ -252,53 +271,67 @@ struct DensityAddOperationExecutor { BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT; add_inputs.fallback_curve_length = brush_settings_->curve_length; add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve); - add_inputs.surface = surface_; - add_inputs.surface_bvh = &surface_bvh_; - add_inputs.surface_looptris = surface_looptris_; - add_inputs.surface_uv_map = surface_uv_map; + add_inputs.transforms = &transforms_; + add_inputs.surface = surface_orig_; add_inputs.corner_normals_su = corner_normals_su; - add_inputs.curves_to_surface_mat = transforms_.curves_to_surface; - add_inputs.surface_to_curves_normal_mat = transforms_.surface_to_curves_normal; - add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_; + add_inputs.reverse_uv_sampler = &reverse_uv_sampler; + add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_; - geometry::add_curves_on_mesh(*curves_, add_inputs); + geometry::add_curves_on_mesh(*curves_orig_, add_inputs); - DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); + DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_orig_->id); ED_region_tag_redraw(ctx_.region); } - void ensure_curve_roots_kdtree() + void prepare_curve_roots_kdtrees() { - if (self_->curve_roots_kdtree_ == nullptr) { - self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_->curves_num()); - for (const int curve_i : curves_->curves_range()) { - const int root_point_i = curves_->offsets()[curve_i]; - const float3 &root_pos_cu = curves_->positions()[root_point_i]; - BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu); + const bke::crazyspace::GeometryDeformation deformation = + bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_); + const Span curve_offsets = curves_orig_->offsets(); + const Span original_positions = curves_orig_->positions(); + const Span deformed_positions = deformation.positions; + BLI_assert(original_positions.size() == deformed_positions.size()); + + auto roots_kdtree_from_positions = [&](const Span positions) { + KDTree_3d *kdtree = BLI_kdtree_3d_new(curves_orig_->curves_num()); + for (const int curve_i : curves_orig_->curves_range()) { + const int root_point_i = curve_offsets[curve_i]; + BLI_kdtree_3d_insert(kdtree, curve_i, positions[root_point_i]); } - BLI_kdtree_3d_balance(self_->curve_roots_kdtree_); - } + BLI_kdtree_3d_balance(kdtree); + return kdtree; + }; + + threading::parallel_invoke( + [&]() { + self_->original_curve_roots_kdtree_ = roots_kdtree_from_positions(original_positions); + }, + [&]() { + self_->deformed_curve_roots_kdtree_ = roots_kdtree_from_positions(deformed_positions); + }); } void sample_projected_with_symmetry(RandomNumberGenerator &rng, - Vector &r_bary_coords, - Vector &r_looptri_indices, + Vector &r_uvs, Vector &r_positions_su) { float4x4 projection; - ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values); const Vector symmetry_brush_transforms = get_symmetry_brush_transforms( - eCurvesSymmetryType(curves_id_->symmetry)); + eCurvesSymmetryType(curves_id_orig_->symmetry)); for (const float4x4 &brush_transform : symmetry_brush_transforms) { const float4x4 brush_transform_inv = brush_transform.inverted(); const float4x4 transform = transforms_.curves_to_surface * brush_transform * transforms_.world_to_curves; + Vector positions_su; + Vector bary_coords; + Vector looptri_indices; const int new_points = bke::mesh_surface_sample::sample_surface_points_projected( rng, - *surface_, - surface_bvh_, + *surface_eval_, + surface_bvh_eval_, brush_pos_re_, brush_radius_re_, [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) { @@ -311,14 +344,13 @@ struct DensityAddOperationExecutor { true, brush_settings_->density_add_attempts, brush_settings_->density_add_attempts, - r_bary_coords, - r_looptri_indices, - r_positions_su); + bary_coords, + looptri_indices, + positions_su); /* Remove some sampled points randomly based on the brush falloff and strength. */ - const int old_points = r_bary_coords.size() - new_points; - for (int i = r_bary_coords.size() - 1; i >= old_points; i--) { - const float3 pos_su = r_positions_su[i]; + for (int i = new_points - 1; i >= 0; i--) { + const float3 pos_su = positions_su[i]; const float3 pos_cu = brush_transform_inv * transforms_.surface_to_curves * pos_su; float2 pos_re; ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); @@ -327,24 +359,30 @@ struct DensityAddOperationExecutor { brush_, dist_to_brush_re, brush_radius_re_); const float weight = brush_strength_ * radius_falloff; if (rng.get_float() > weight) { - r_bary_coords.remove_and_reorder(i); - r_looptri_indices.remove_and_reorder(i); - r_positions_su.remove_and_reorder(i); + bary_coords.remove_and_reorder(i); + looptri_indices.remove_and_reorder(i); + positions_su.remove_and_reorder(i); } } + + for (const int i : bary_coords.index_range()) { + const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords( + bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_); + r_uvs.append(uv); + } + r_positions_su.extend(positions_su); } } void sample_spherical_with_symmetry(RandomNumberGenerator &rng, - Vector &r_bary_coords, - Vector &r_looptri_indices, + Vector &r_uvs, Vector &r_positions_su) { const std::optional brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph, *ctx_.region, *ctx_.v3d, transforms_, - surface_bvh_, + surface_bvh_eval_, brush_pos_re_, brush_radius_re_); if (!brush_3d.has_value()) { @@ -352,7 +390,7 @@ struct DensityAddOperationExecutor { } const Vector symmetry_brush_transforms = get_symmetry_brush_transforms( - eCurvesSymmetryType(curves_id_->symmetry)); + eCurvesSymmetryType(curves_id_orig_->symmetry)); for (const float4x4 &brush_transform : symmetry_brush_transforms) { const float3 brush_pos_cu = brush_transform * brush_3d->position_cu; const float3 brush_pos_su = transforms_.curves_to_surface * brush_pos_cu; @@ -360,45 +398,54 @@ struct DensityAddOperationExecutor { transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu); const float brush_radius_sq_su = pow2f(brush_radius_su); - Vector looptri_indices; + Vector selected_looptri_indices; BLI_bvhtree_range_query_cpp( - *surface_bvh_.tree, + *surface_bvh_eval_.tree, brush_pos_su, brush_radius_su, [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) { - looptri_indices.append(index); + selected_looptri_indices.append(index); }); const float brush_plane_area_su = M_PI * brush_radius_sq_su; const float approximate_density_su = brush_settings_->density_add_attempts / brush_plane_area_su; + Vector positions_su; + Vector bary_coords; + Vector looptri_indices; const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical( rng, - *surface_, - looptri_indices, + *surface_eval_, + selected_looptri_indices, brush_pos_su, brush_radius_su, approximate_density_su, - r_bary_coords, - r_looptri_indices, - r_positions_su); + bary_coords, + looptri_indices, + positions_su); /* Remove some sampled points randomly based on the brush falloff and strength. */ - const int old_points = r_bary_coords.size() - new_points; - for (int i = r_bary_coords.size() - 1; i >= old_points; i--) { - const float3 pos_su = r_positions_su[i]; + for (int i = new_points - 1; i >= 0; i--) { + const float3 pos_su = positions_su[i]; const float3 pos_cu = transforms_.surface_to_curves * pos_su; const float dist_to_brush_cu = math::distance(pos_cu, brush_pos_cu); const float radius_falloff = BKE_brush_curve_strength( brush_, dist_to_brush_cu, brush_3d->radius_cu); const float weight = brush_strength_ * radius_falloff; if (rng.get_float() > weight) { - r_bary_coords.remove_and_reorder(i); - r_looptri_indices.remove_and_reorder(i); - r_positions_su.remove_and_reorder(i); + bary_coords.remove_and_reorder(i); + looptri_indices.remove_and_reorder(i); + positions_su.remove_and_reorder(i); } } + + for (const int i : bary_coords.index_range()) { + const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords( + bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_); + r_uvs.append(uv); + } + r_positions_su.extend(positions_su); } } }; @@ -414,6 +461,13 @@ class DensitySubtractOperation : public CurvesSculptStrokeOperation { private: friend struct DensitySubtractOperationExecutor; + /** + * Deformed root positions of curves that still exist. This has to be stored in case the brush is + * executed more than once before the curves are evaluated again. This can happen when the mouse + * is moved quickly and the brush spacing is small. + */ + Vector deformed_root_positions_; + public: void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override; }; @@ -433,8 +487,12 @@ struct DensitySubtractOperationExecutor { Vector selected_curve_indices_; IndexMask curve_selection_; - Object *surface_ob_ = nullptr; - Mesh *surface_ = nullptr; + Object *surface_ob_orig_ = nullptr; + Mesh *surface_orig_ = nullptr; + + Object *surface_ob_eval_ = nullptr; + Mesh *surface_eval_ = nullptr; + BVHTreeFromMesh surface_bvh_eval_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -446,7 +504,6 @@ struct DensitySubtractOperationExecutor { float minimum_distance_; CurvesSurfaceTransforms transforms_; - BVHTreeFromMesh surface_bvh_; KDTree_3d *root_points_kdtree_; @@ -468,11 +525,20 @@ struct DensitySubtractOperationExecutor { return; } - surface_ob_ = curves_id_->surface; - if (surface_ob_ == nullptr) { + surface_ob_orig_ = curves_id_->surface; + if (surface_ob_orig_ == nullptr) { + return; + } + surface_orig_ = static_cast(surface_ob_orig_->data); + + surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_); + if (surface_ob_eval_ == nullptr) { return; } - surface_ = static_cast(surface_ob_->data); + surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_); + + BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2); + BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); }); curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); @@ -488,16 +554,20 @@ struct DensitySubtractOperationExecutor { transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface); const eBrushFalloffShape falloff_shape = static_cast( brush_->falloff_shape); - BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); - BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); }); - const Span positions_cu = curves_->positions(); + if (stroke_extension.is_first) { + const bke::crazyspace::GeometryDeformation deformation = + bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_); + for (const int curve_i : curves_->curves_range()) { + const int first_point_i = curves_->offsets()[curve_i]; + self_->deformed_root_positions_.append(deformation.positions[first_point_i]); + } + } root_points_kdtree_ = BLI_kdtree_3d_new(curve_selection_.size()); BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(root_points_kdtree_); }); for (const int curve_i : curve_selection_) { - const int first_point_i = curves_->offsets()[curve_i]; - const float3 &pos_cu = positions_cu[first_point_i]; + const float3 &pos_cu = self_->deformed_root_positions_[curve_i]; BLI_kdtree_3d_insert(root_points_kdtree_, curve_i, pos_cu); } BLI_kdtree_3d_balance(root_points_kdtree_); @@ -515,12 +585,23 @@ struct DensitySubtractOperationExecutor { } Vector indices; - const IndexMask mask = index_mask_ops::find_indices_based_on_predicate( + const IndexMask mask_to_delete = index_mask_ops::find_indices_based_on_predicate( curves_->curves_range(), 4096, indices, [&](const int curve_i) { return curves_to_delete[curve_i]; }); - curves_->remove_curves(mask); + /* Remove deleted curves fromt he stored deformed root positions. */ + const Vector ranges_to_keep = mask_to_delete.extract_ranges_invert( + curves_->curves_range()); + BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size()); + Vector new_deformed_positions; + for (const IndexRange range : ranges_to_keep) { + new_deformed_positions.extend(self_->deformed_root_positions_.as_span().slice(range)); + } + self_->deformed_root_positions_ = std::move(new_deformed_positions); + + curves_->remove_curves(mask_to_delete); + BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size()); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); @@ -539,15 +620,12 @@ struct DensitySubtractOperationExecutor { void reduce_density_projected(const float4x4 &brush_transform, MutableSpan curves_to_delete) { - const Span positions_cu = curves_->positions(); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); float4x4 projection; ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); - const Span offsets = curves_->offsets(); - /* Randomly select the curves that are allowed to be removed, based on the brush radius and * strength. */ Array allow_remove_curve(curves_->curves_num(), false); @@ -559,8 +637,7 @@ struct DensitySubtractOperationExecutor { allow_remove_curve[curve_i] = true; continue; } - const int first_point_i = offsets[curve_i]; - const float3 pos_cu = brush_transform * positions_cu[first_point_i]; + const float3 pos_cu = brush_transform * self_->deformed_root_positions_[curve_i]; float2 pos_re; ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); @@ -586,8 +663,7 @@ struct DensitySubtractOperationExecutor { if (!allow_remove_curve[curve_i]) { continue; } - const int first_point_i = offsets[curve_i]; - const float3 orig_pos_cu = positions_cu[first_point_i]; + const float3 orig_pos_cu = self_->deformed_root_positions_[curve_i]; const float3 pos_cu = brush_transform * orig_pos_cu; float2 pos_re; ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); @@ -618,7 +694,7 @@ struct DensitySubtractOperationExecutor { *ctx_.region, *ctx_.v3d, transforms_, - surface_bvh_, + surface_bvh_eval_, brush_pos_re_, brush_radius_re); if (!brush_3d.has_value()) { @@ -638,8 +714,6 @@ struct DensitySubtractOperationExecutor { MutableSpan curves_to_delete) { const float brush_radius_sq_cu = pow2f(brush_radius_cu); - const Span positions_cu = curves_->positions(); - const Span offsets = curves_->offsets(); /* Randomly select the curves that are allowed to be removed, based on the brush radius and * strength. */ @@ -652,8 +726,7 @@ struct DensitySubtractOperationExecutor { allow_remove_curve[curve_i] = true; continue; } - const int first_point_i = offsets[curve_i]; - const float3 pos_cu = positions_cu[first_point_i]; + const float3 pos_cu = self_->deformed_root_positions_[curve_i]; const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu); if (dist_to_brush_sq_cu > brush_radius_sq_cu) { @@ -677,8 +750,7 @@ struct DensitySubtractOperationExecutor { if (!allow_remove_curve[curve_i]) { continue; } - const int first_point_i = offsets[curve_i]; - const float3 &pos_cu = positions_cu[first_point_i]; + const float3 &pos_cu = self_->deformed_root_positions_[curve_i]; const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu); if (dist_to_brush_sq_cu > brush_radius_sq_cu) { continue; @@ -717,6 +789,10 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode, { const Scene &scene = *CTX_data_scene(&C); const Brush &brush = *BKE_paint_brush_for_read(&scene.toolsettings->curves_sculpt->paint); + const Depsgraph &depsgraph = *CTX_data_depsgraph_on_load(&C); + const ARegion ®ion = *CTX_wm_region(&C); + const View3D &v3d = *CTX_wm_view3d(&C); + const eBrushCurvesSculptDensityMode density_mode = static_cast( brush.curves_sculpt_settings->density_mode); const bool use_invert = brush_mode == BRUSH_STROKE_INVERT; @@ -728,26 +804,29 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode, return use_invert; } - const Object &curves_ob = *CTX_data_active_object(&C); - const Curves &curves_id = *static_cast(curves_ob.data); - const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); - if (curves_id.surface == nullptr) { - /* The brush won't do anything in this case anyway. */ + const Object &curves_ob_orig = *CTX_data_active_object(&C); + const Curves &curves_id_orig = *static_cast(curves_ob_orig.data); + Object *surface_ob_orig = curves_id_orig.surface; + if (surface_ob_orig == nullptr) { return true; } + Object *surface_ob_eval = DEG_get_evaluated_object(&depsgraph, surface_ob_orig); + if (surface_ob_eval == nullptr) { + return true; + } + const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id_orig.geometry); if (curves.curves_num() <= 1) { return true; } + const Mesh *surface_mesh_eval = BKE_object_get_evaluated_mesh(surface_ob_eval); + if (surface_mesh_eval == nullptr) { + return true; + } - const CurvesSurfaceTransforms transforms(curves_ob, curves_id.surface); - BVHTreeFromMesh surface_bvh; - BKE_bvhtree_from_mesh_get( - &surface_bvh, static_cast(curves_id.surface->data), BVHTREE_FROM_LOOPTRI, 2); - BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); }); - - const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C); - const ARegion ®ion = *CTX_wm_region(&C); - const View3D &v3d = *CTX_wm_view3d(&C); + const CurvesSurfaceTransforms transforms(curves_ob_orig, curves_id_orig.surface); + BVHTreeFromMesh surface_bvh_eval; + BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_mesh_eval, BVHTREE_FROM_LOOPTRI, 2); + BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); }); const float2 brush_pos_re = stroke_start.mouse_position; /* Reduce radius so that only an inner circle is used to determine the existing density. */ @@ -755,7 +834,7 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode, /* Find the surface point under the brush. */ const std::optional brush_3d = sample_curves_surface_3d_brush( - depsgraph, region, v3d, transforms, surface_bvh, brush_pos_re, brush_radius_re); + depsgraph, region, v3d, transforms, surface_bvh_eval, brush_pos_re, brush_radius_re); if (!brush_3d.has_value()) { return true; } @@ -764,8 +843,9 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode, const float brush_radius_cu = brush_3d->radius_cu; const float brush_radius_sq_cu = pow2f(brush_radius_cu); + const bke::crazyspace::GeometryDeformation deformation = + bke::crazyspace::get_evaluated_curves_deformation(depsgraph, curves_ob_orig); const Span offsets = curves.offsets(); - const Span positions_cu = curves.positions(); /* Compute distance from brush to curve roots. */ Array> distances_sq_to_brush(curves.curves_num()); @@ -774,7 +854,7 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode, int &valid_curve_count = valid_curve_count_by_thread.local(); for (const int curve_i : range) { const int root_point_i = offsets[curve_i]; - const float3 &root_pos_cu = positions_cu[root_point_i]; + const float3 &root_pos_cu = deformation.positions[root_point_i]; const float dist_sq_cu = math::distance_squared(root_pos_cu, brush_pos_cu); if (dist_sq_cu < brush_radius_sq_cu) { distances_sq_to_brush[curve_i] = {math::distance_squared(root_pos_cu, brush_pos_cu), @@ -799,9 +879,9 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode, * center. */ float min_dist_sq_cu = FLT_MAX; for (const int i : IndexRange(check_curve_count)) { - const float3 &pos_i = positions_cu[offsets[distances_sq_to_brush[i].second]]; + const float3 &pos_i = deformation.positions[offsets[distances_sq_to_brush[i].second]]; for (int j = i + 1; j < check_curve_count; j++) { - const float3 &pos_j = positions_cu[offsets[distances_sq_to_brush[j].second]]; + const float3 &pos_j = deformation.positions[offsets[distances_sq_to_brush[j].second]]; const float dist_sq_cu = math::distance_squared(pos_i, pos_j); math::min_inplace(min_dist_sq_cu, dist_sq_cu); } -- cgit v1.2.3