diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r-- | source/blender/editors/sculpt_paint/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_add.cc | 697 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_brush.cc | 96 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_comb.cc | 20 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_delete.cc | 10 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc | 22 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_intern.hh | 42 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc | 14 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc | 21 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc (renamed from source/blender/editors/sculpt_paint/paint_vertex_color_ops.c) | 58 |
10 files changed, 290 insertions, 692 deletions
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b1b52d16c6d..8879161d2af 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -52,7 +52,7 @@ set(SRC paint_stroke.c paint_utils.c paint_vertex.cc - paint_vertex_color_ops.c + paint_vertex_color_ops.cc paint_vertex_color_utils.c paint_vertex_proj.c paint_vertex_weight_ops.c diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index f013fa05f4c..bac03de77e7 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -22,9 +22,9 @@ #include "BKE_geometry_set.hh" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" +#include "BKE_mesh_sample.hh" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_spline.hh" #include "DNA_brush_enums.h" #include "DNA_brush_types.h" @@ -38,10 +38,12 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "GEO_add_curves_on_mesh.hh" + #include "WM_api.h" /** - * The code below uses a prefix naming convention to indicate the coordinate space: + * The code below uses a suffix naming convention to indicate the coordinate space: * cu: Local space of the curves object that is being edited. * su: Local space of the surface object. * wo: World space. @@ -70,16 +72,6 @@ class AddOperation : public CurvesSculptStrokeOperation { void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override; }; -static void initialize_straight_curve_positions(const float3 &p1, - const float3 &p2, - MutableSpan<float3> r_positions) -{ - const float step = 1.0f / (float)(r_positions.size() - 1); - for (const int i : r_positions.index_range()) { - r_positions[i] = math::interpolate(p1, p2, i * step); - } -} - /** * Utility class that actually executes the update when the stroke is updated. That's useful * because it avoids passing a very large number of parameters between functions. @@ -95,54 +87,26 @@ struct AddOperationExecutor { Object *surface_ob_ = nullptr; Mesh *surface_ = nullptr; Span<MLoopTri> surface_looptris_; - Span<float3> corner_normals_su_; - VArray_Span<float2> surface_uv_map_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; const BrushCurvesSculptSettings *brush_settings_ = nullptr; + int add_amount_; + bool use_front_face_; float brush_radius_re_; float2 brush_pos_re_; - bool use_front_face_; - bool interpolate_length_; - bool interpolate_shape_; - bool interpolate_point_count_; - bool use_interpolation_; - float new_curve_length_; - int add_amount_; - int constant_points_per_curve_; - - /** Various matrices to convert between coordinate spaces. */ - float4x4 curves_to_world_mat_; - float4x4 curves_to_surface_mat_; - float4x4 world_to_curves_mat_; - float4x4 world_to_surface_mat_; - float4x4 surface_to_world_mat_; - float4x4 surface_to_curves_mat_; - float4x4 surface_to_curves_normal_mat_; + CurvesSculptTransforms transforms_; BVHTreeFromMesh surface_bvh_; - int tot_old_curves_; - int tot_old_points_; - struct AddedPoints { Vector<float3> positions_cu; Vector<float3> bary_coords; Vector<int> looptri_indices; }; - struct NeighborInfo { - /* Curve index of the neighbor. */ - int index; - /* The weights of all neighbors of a new curve add up to 1. */ - float weight; - }; - static constexpr int max_neighbors = 5; - using NeighborsVector = Vector<NeighborInfo, max_neighbors>; - AddOperationExecutor(const bContext &C) : ctx_(C) { } @@ -159,23 +123,10 @@ struct AddOperationExecutor { return; } - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); surface_ob_ = curves_id_->surface; surface_ = static_cast<Mesh *>(surface_ob_->data); - surface_to_world_mat_ = surface_ob_->obmat; - world_to_surface_mat_ = surface_to_world_mat_.inverted(); - surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_; - surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed(); - curves_to_surface_mat_ = world_to_surface_mat_ * curves_to_world_mat_; - - if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { - BKE_mesh_calc_normals_split(surface_); - } - corner_normals_su_ = { - reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), - surface_->totloop}; curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); @@ -187,16 +138,6 @@ struct AddOperationExecutor { const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( brush_->falloff_shape); add_amount_ = std::max(0, brush_settings_->add_amount); - constant_points_per_curve_ = std::max(2, brush_settings_->points_per_curve); - interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH; - interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE; - interpolate_point_count_ = brush_settings_->flag & - BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT; - use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_; - new_curve_length_ = brush_settings_->curve_length; - - tot_old_curves_ = curves_->curves_num(); - tot_old_points_ = curves_->points_num(); if (add_amount_ == 0) { return; @@ -212,15 +153,6 @@ struct AddOperationExecutor { surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_), BKE_mesh_runtime_looptri_len(surface_)}; - if (curves_id_->surface_uv_map != nullptr) { - MeshComponent surface_component; - surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); - surface_uv_map_ = surface_component - .attribute_try_get_for_read(curves_id_->surface_uv_map, - ATTR_DOMAIN_CORNER) - .typed<float2>(); - } - /* Sample points on the surface using one of multiple strategies. */ AddedPoints added_points; if (add_amount_ == 1) { @@ -241,28 +173,52 @@ struct AddOperationExecutor { return; } - Array<NeighborsVector> neighbors_per_curve; - if (use_interpolation_) { - this->ensure_curve_roots_kdtree(); - neighbors_per_curve = this->find_curve_neighbors(added_points); + /* Find UV map. */ + VArray_Span<float2> surface_uv_map; + if (curves_id_->surface_uv_map != nullptr) { + MeshComponent surface_component; + surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); + surface_uv_map = surface_component + .attribute_try_get_for_read(curves_id_->surface_uv_map, + ATTR_DOMAIN_CORNER) + .typed<float2>(); } - /* Resize to add the new curves, building the offsets in the array owned by the curves. */ - const int tot_added_curves = added_points.bary_coords.size(); - curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves); - if (interpolate_point_count_) { - this->initialize_curve_offsets_with_interpolation(neighbors_per_curve); - } - else { - this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_); + /* Find normals. */ + if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { + BKE_mesh_calc_normals_split(surface_); } + const Span<float3> corner_normals_su = { + reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), + surface_->totloop}; - /* Resize to add the correct point count calculated as part of building the offsets. */ - curves_->resize(curves_->offsets().last(), curves_->curves_num()); - - this->initialize_attributes(added_points, neighbors_per_curve); + geometry::AddCurvesOnMeshInputs add_inputs; + add_inputs.root_positions_cu = added_points.positions_cu; + add_inputs.bary_coords = added_points.bary_coords; + add_inputs.looptri_indices = added_points.looptri_indices; + add_inputs.interpolate_length = brush_settings_->flag & + BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH; + add_inputs.interpolate_shape = brush_settings_->flag & + BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE; + add_inputs.interpolate_point_count = brush_settings_->flag & + 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.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; + + if (add_inputs.interpolate_length || add_inputs.interpolate_shape || + add_inputs.interpolate_point_count) { + this->ensure_curve_roots_kdtree(); + add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_; + } - curves_->update_curve_types(); + geometry::add_curves_on_mesh(*curves_, add_inputs); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); @@ -277,14 +233,14 @@ struct AddOperationExecutor { float3 ray_start_wo, ray_end_wo; ED_view3d_win_to_segment_clipped( ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true); - const float3 ray_start_cu = world_to_curves_mat_ * ray_start_wo; - const float3 ray_end_cu = world_to_curves_mat_ * ray_end_wo; + const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo; + const float3 ray_end_cu = transforms_.world_to_curves * ray_end_wo; const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); for (const float4x4 &brush_transform : symmetry_brush_transforms) { - const float4x4 transform = curves_to_surface_mat_ * brush_transform; + const float4x4 transform = transforms_.curves_to_surface * brush_transform; this->sample_in_center(r_added_points, transform * ray_start_cu, transform * ray_end_cu); } } @@ -312,10 +268,10 @@ struct AddOperationExecutor { const int looptri_index = ray_hit.index; const float3 brush_pos_su = ray_hit.co; - const float3 bary_coords = compute_bary_coord_in_triangle( + const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle( *surface_, surface_looptris_[looptri_index], brush_pos_su); - const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su; + const float3 brush_pos_cu = transforms_.surface_to_curves * brush_pos_su; r_added_points.positions_cu.append(brush_pos_cu); r_added_points.bary_coords.append(bary_coords); @@ -339,60 +295,37 @@ struct AddOperationExecutor { const float4x4 &brush_transform) { const int old_amount = r_added_points.bary_coords.size(); - const int max_iterations = std::max(100'000, add_amount_ * 10); + const int max_iterations = 100; int current_iteration = 0; while (r_added_points.bary_coords.size() < old_amount + add_amount_) { if (current_iteration++ >= max_iterations) { break; } - - const float r = brush_radius_re_ * std::sqrt(rng.get_float()); - const float angle = rng.get_float() * 2.0f * M_PI; - const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle)); - - float3 ray_start_wo, ray_end_wo; - ED_view3d_win_to_segment_clipped( - ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, ray_start_wo, ray_end_wo, true); - const float3 ray_start_cu = brush_transform * (world_to_curves_mat_ * ray_start_wo); - const float3 ray_end_cu = brush_transform * (world_to_curves_mat_ * ray_end_wo); - - const float3 ray_start_su = curves_to_surface_mat_ * ray_start_cu; - const float3 ray_end_su = curves_to_surface_mat_ * ray_end_cu; - const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su); - - BVHTreeRayHit ray_hit; - ray_hit.dist = FLT_MAX; - ray_hit.index = -1; - BLI_bvhtree_ray_cast(surface_bvh_.tree, - ray_start_su, - ray_direction_su, - 0.0f, - &ray_hit, - surface_bvh_.raycast_callback, - &surface_bvh_); - - if (ray_hit.index == -1) { - continue; - } - - if (use_front_face_) { - const float3 normal_su = ray_hit.no; - if (math::dot(ray_direction_su, normal_su) >= 0.0f) { - continue; - } + const int missing_amount = add_amount_ + old_amount - r_added_points.bary_coords.size(); + const int new_points = bke::mesh_surface_sample::sample_surface_points_projected( + rng, + *surface_, + surface_bvh_, + brush_pos_re_, + brush_radius_re_, + [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) { + float3 start_wo, end_wo; + ED_view3d_win_to_segment_clipped( + ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true); + const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo); + const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo); + r_start_su = transforms_.curves_to_surface * start_cu; + r_end_su = transforms_.curves_to_surface * end_cu; + }, + use_front_face_, + add_amount_, + missing_amount, + r_added_points.bary_coords, + r_added_points.looptri_indices, + r_added_points.positions_cu); + for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) { + pos = transforms_.surface_to_curves * pos; } - - const int looptri_index = ray_hit.index; - const float3 pos_su = ray_hit.co; - - const float3 bary_coords = compute_bary_coord_in_triangle( - *surface_, surface_looptris_[looptri_index], pos_su); - - const float3 pos_cu = surface_to_curves_mat_ * pos_su; - - r_added_points.positions_cu.append(pos_cu); - r_added_points.bary_coords.append(bary_coords); - r_added_points.looptri_indices.append(looptri_index); } } @@ -401,72 +334,47 @@ struct AddOperationExecutor { */ void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points) { - /* Find ray that starts in the center of the brush. */ - float3 brush_ray_start_wo, brush_ray_end_wo; - ED_view3d_win_to_segment_clipped(ctx_.depsgraph, - ctx_.region, - ctx_.v3d, - brush_pos_re_, - brush_ray_start_wo, - brush_ray_end_wo, - true); - const float3 brush_ray_start_cu = world_to_curves_mat_ * brush_ray_start_wo; - const float3 brush_ray_end_cu = world_to_curves_mat_ * brush_ray_end_wo; + const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + transforms_, + surface_bvh_, + brush_pos_re_, + brush_radius_re_); + if (!brush_3d.has_value()) { + return; + } - /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius - * in 3D. */ - float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo; + float3 view_ray_start_wo, view_ray_end_wo; ED_view3d_win_to_segment_clipped(ctx_.depsgraph, ctx_.region, ctx_.v3d, - brush_pos_re_ + float2(brush_radius_re_, 0), - brush_radius_ray_start_wo, - brush_radius_ray_end_wo, + brush_pos_re_, + view_ray_start_wo, + view_ray_end_wo, true); - const float3 brush_radius_ray_start_cu = world_to_curves_mat_ * brush_radius_ray_start_wo; - const float3 brush_radius_ray_end_cu = world_to_curves_mat_ * brush_radius_ray_end_wo; + const float3 view_direction_su = math::normalize( + transforms_.world_to_surface * view_ray_end_wo - + transforms_.world_to_surface * view_ray_start_wo); const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); for (const float4x4 &brush_transform : symmetry_brush_transforms) { - const float4x4 transform = curves_to_surface_mat_ * brush_transform; - this->sample_spherical(rng, - r_added_points, - transform * brush_ray_start_cu, - transform * brush_ray_end_cu, - transform * brush_radius_ray_start_cu, - transform * brush_radius_ray_end_cu); + const float4x4 transform = transforms_.curves_to_surface * brush_transform; + const float3 brush_pos_su = transform * brush_3d->position_cu; + const float brush_radius_su = transform_brush_radius( + transform, brush_3d->position_cu, brush_3d->radius_cu); + this->sample_spherical( + rng, r_added_points, brush_pos_su, brush_radius_su, view_direction_su); } } void sample_spherical(RandomNumberGenerator &rng, AddedPoints &r_added_points, - const float3 &brush_ray_start_su, - const float3 &brush_ray_end_su, - const float3 &brush_radius_ray_start_su, - const float3 &brush_radius_ray_end_su) + const float3 &brush_pos_su, + const float brush_radius_su, + const float3 &view_direction_su) { - const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su); - - BVHTreeRayHit ray_hit; - ray_hit.dist = FLT_MAX; - ray_hit.index = -1; - BLI_bvhtree_ray_cast(surface_bvh_.tree, - brush_ray_start_su, - brush_ray_direction_su, - 0.0f, - &ray_hit, - surface_bvh_.raycast_callback, - &surface_bvh_); - - if (ray_hit.index == -1) { - return; - } - - /* Compute brush radius. */ - const float3 brush_pos_su = ray_hit.co; - const float brush_radius_su = dist_to_line_v3( - brush_pos_su, brush_radius_ray_start_su, brush_radius_ray_end_su); const float brush_radius_sq_su = pow2f(brush_radius_su); /* Find surface triangles within brush radius. */ @@ -483,7 +391,7 @@ struct AddOperationExecutor { const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co; float3 normal_su; normal_tri_v3(normal_su, v0_su, v1_su, v2_su); - if (math::dot(normal_su, brush_ray_direction_su) >= 0.0f) { + if (math::dot(normal_su, view_direction_su) >= 0.0f) { return; } looptri_indices.append(index); @@ -505,9 +413,6 @@ struct AddOperationExecutor { const float brush_plane_area_su = M_PI * brush_radius_sq_su; const float approximate_density_su = add_amount_ / brush_plane_area_su; - /* Used for switching between two triangle sampling strategies. */ - const float area_threshold = brush_plane_area_su; - /* Usually one or two iterations should be enough. */ const int max_iterations = 5; int current_iteration = 0; @@ -517,78 +422,18 @@ struct AddOperationExecutor { if (current_iteration++ >= max_iterations) { break; } - - for (const int looptri_index : looptri_indices) { - const MLoopTri &looptri = surface_looptris_[looptri_index]; - - const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co; - const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co; - const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co; - - const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su); - - if (looptri_area_su < area_threshold) { - /* The triangle is small compared to the brush radius. Sample by generating random - * barycentric coordinates. */ - const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su); - for ([[maybe_unused]] const int i : IndexRange(amount)) { - const float3 bary_coord = rng.get_barycentric_coordinates(); - const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su); - const float distance_to_brush_sq_su = math::distance_squared(point_pos_su, - brush_pos_su); - if (distance_to_brush_sq_su > brush_radius_sq_su) { - continue; - } - - r_added_points.bary_coords.append(bary_coord); - r_added_points.looptri_indices.append(looptri_index); - r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su); - } - } - else { - /* The triangle is large compared to the brush radius. Sample by generating random points - * on the triangle plane within the brush radius. */ - float3 normal_su; - normal_tri_v3(normal_su, v0_su, v1_su, v2_su); - - float3 brush_pos_proj_su = brush_pos_su; - project_v3_plane(brush_pos_proj_su, normal_su, v0_su); - - const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su, - brush_pos_su); - const float brush_radius_factor_sq = 1.0f - - std::min(1.0f, - proj_distance_sq_su / brush_radius_sq_su); - const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq; - const float radius_proj_su = std::sqrt(radius_proj_sq_su); - const float circle_area_su = M_PI * radius_proj_su; - - const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su); - - const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su; - const float3 axis_2_su = math::normalize(math::cross( - axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) * - radius_proj_su; - - for ([[maybe_unused]] const int i : IndexRange(amount)) { - const float r = std::sqrt(rng.get_float()); - const float angle = rng.get_float() * 2.0f * M_PI; - const float x = r * std::cos(angle); - const float y = r * std::sin(angle); - const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y; - if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) { - /* Sampled point is not in the triangle. */ - continue; - } - - float3 bary_coord; - interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su); - - r_added_points.bary_coords.append(bary_coord); - r_added_points.looptri_indices.append(looptri_index); - r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su); - } - } + const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical( + rng, + *surface_, + looptri_indices, + brush_pos_su, + brush_radius_su, + approximate_density_su, + r_added_points.bary_coords, + r_added_points.looptri_indices, + r_added_points.positions_cu); + for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) { + pos = transforms_.surface_to_curves * pos; } } @@ -613,312 +458,6 @@ struct AddOperationExecutor { BLI_kdtree_3d_balance(self_->curve_roots_kdtree_); } } - - void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve) - { - MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_); - - attribute_math::DefaultMixer<int> mixer{new_offsets}; - threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) { - for (const int i : curves_range) { - if (neighbors_per_curve[i].is_empty()) { - mixer.mix_in(i, constant_points_per_curve_, 1.0f); - } - else { - for (const NeighborInfo &neighbor : neighbors_per_curve[i]) { - const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size(); - mixer.mix_in(i, neighbor_points_num, neighbor.weight); - } - } - } - }); - mixer.finalize(); - - bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_); - } - - void initialize_curve_offsets_without_interpolation(const int points_per_curve) - { - MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_); - int offset = tot_old_points_; - for (const int i : new_offsets.index_range()) { - new_offsets[i] = offset; - offset += points_per_curve; - } - } - - void initialize_attributes(const AddedPoints &added_points, - const Span<NeighborsVector> neighbors_per_curve) - { - Array<float> new_lengths_cu(added_points.bary_coords.size()); - if (interpolate_length_) { - this->interpolate_lengths(neighbors_per_curve, new_lengths_cu); - } - else { - new_lengths_cu.fill(new_curve_length_); - } - - Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points); - if (!surface_uv_map_.is_empty()) { - this->initialize_surface_attachment(added_points); - } - - this->fill_new_selection(); - - if (interpolate_shape_) { - this->initialize_position_with_interpolation( - added_points, neighbors_per_curve, new_normals_su, new_lengths_cu); - } - else { - this->initialize_position_without_interpolation( - added_points, new_lengths_cu, new_normals_su); - } - } - - /** - * Select newly created points or curves in new curves if necessary. - */ - void fill_new_selection() - { - switch (curves_id_->selection_domain) { - case ATTR_DOMAIN_CURVE: { - const VArray<float> selection = curves_->selection_curve_float(); - if (selection.is_single() && selection.get_internal_single() >= 1.0f) { - return; - } - curves_->selection_curve_float_for_write().drop_front(tot_old_curves_).fill(1.0f); - break; - } - case ATTR_DOMAIN_POINT: { - const VArray<float> selection = curves_->selection_point_float(); - if (selection.is_single() && selection.get_internal_single() >= 1.0f) { - return; - } - curves_->selection_point_float_for_write().drop_front(tot_old_points_).fill(1.0f); - break; - } - default: - BLI_assert_unreachable(); - } - } - - Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points) - { - const int tot_added_curves = added_points.bary_coords.size(); - Array<NeighborsVector> neighbors_per_curve(tot_added_curves); - threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) { - for (const int i : range) { - const float3 root_cu = added_points.positions_cu[i]; - std::array<KDTreeNearest_3d, max_neighbors> nearest_n; - const int found_neighbors = BLI_kdtree_3d_find_nearest_n( - self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors); - float tot_weight = 0.0f; - for (const int neighbor_i : IndexRange(found_neighbors)) { - KDTreeNearest_3d &nearest = nearest_n[neighbor_i]; - const float weight = 1.0f / std::max(nearest.dist, 0.00001f); - tot_weight += weight; - neighbors_per_curve[i].append({nearest.index, weight}); - } - /* Normalize weights. */ - for (NeighborInfo &neighbor : neighbors_per_curve[i]) { - neighbor.weight /= tot_weight; - } - } - }); - return neighbors_per_curve; - } - - void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve, - MutableSpan<float> r_lengths) - { - const Span<float3> positions_cu = curves_->positions(); - - threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) { - for (const int added_curve_i : range) { - const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i]; - float length_sum = 0.0f; - for (const NeighborInfo &neighbor : neighbors) { - const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index); - float neighbor_length = 0.0f; - for (const int segment_i : neighbor_points.drop_back(1)) { - const float3 &p1 = positions_cu[segment_i]; - const float3 &p2 = positions_cu[segment_i + 1]; - neighbor_length += math::distance(p1, p2); - } - length_sum += neighbor.weight * neighbor_length; - } - const float length = neighbors.is_empty() ? new_curve_length_ : length_sum; - r_lengths[added_curve_i] = length; - } - }); - } - - float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord) - { - const MLoopTri &looptri = surface_looptris_[looptri_index]; - const int l0 = looptri.tri[0]; - const int l1 = looptri.tri[1]; - const int l2 = looptri.tri[2]; - - const float3 &l0_normal_su = corner_normals_su_[l0]; - const float3 &l1_normal_su = corner_normals_su_[l1]; - const float3 &l2_normal_su = corner_normals_su_[l2]; - - const float3 normal_su = math::normalize( - attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su)); - return normal_su; - } - - Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points) - { - Array<float3> normals_su(added_points.bary_coords.size()); - threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) { - for (const int i : range) { - const int looptri_index = added_points.looptri_indices[i]; - const float3 &bary_coord = added_points.bary_coords[i]; - normals_su[i] = compute_surface_point_normal( - surface_looptris_[looptri_index], bary_coord, corner_normals_su_); - } - }); - return normals_su; - } - - void initialize_surface_attachment(const AddedPoints &added_points) - { - MutableSpan<float2> surface_uv_coords = curves_->surface_uv_coords_for_write(); - threading::parallel_for( - added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) { - for (const int i : range) { - const int curve_i = tot_old_curves_ + i; - const MLoopTri &looptri = surface_looptris_[added_points.looptri_indices[i]]; - const float2 &uv0 = surface_uv_map_[looptri.tri[0]]; - const float2 &uv1 = surface_uv_map_[looptri.tri[1]]; - const float2 &uv2 = surface_uv_map_[looptri.tri[2]]; - const float3 &bary_coords = added_points.bary_coords[i]; - const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2); - surface_uv_coords[curve_i] = uv; - } - }); - } - - /** - * Initialize new curves so that they are just a straight line in the normal direction. - */ - void initialize_position_without_interpolation(const AddedPoints &added_points, - const Span<float> lengths_cu, - const MutableSpan<float3> normals_su) - { - MutableSpan<float3> positions_cu = curves_->positions_for_write(); - - threading::parallel_for( - added_points.bary_coords.index_range(), 256, [&](const IndexRange range) { - for (const int i : range) { - const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i); - const float3 &root_cu = added_points.positions_cu[i]; - const float length = lengths_cu[i]; - const float3 &normal_su = normals_su[i]; - const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su); - const float3 tip_cu = root_cu + length * normal_cu; - - initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points)); - } - }); - } - - /** - * Use neighboring curves to determine the shape. - */ - void initialize_position_with_interpolation(const AddedPoints &added_points, - const Span<NeighborsVector> neighbors_per_curve, - const Span<float3> new_normals_su, - const Span<float> new_lengths_cu) - { - MutableSpan<float3> positions_cu = curves_->positions_for_write(); - - threading::parallel_for( - added_points.bary_coords.index_range(), 256, [&](const IndexRange range) { - for (const int i : range) { - const Span<NeighborInfo> neighbors = neighbors_per_curve[i]; - const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i); - - const float length_cu = new_lengths_cu[i]; - const float3 &normal_su = new_normals_su[i]; - const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su); - - const float3 &root_cu = added_points.positions_cu[i]; - - if (neighbors.is_empty()) { - /* If there are no neighbors, just make a straight line. */ - const float3 tip_cu = root_cu + length_cu * normal_cu; - initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points)); - continue; - } - - positions_cu.slice(points).fill(root_cu); - - for (const NeighborInfo &neighbor : neighbors) { - const int neighbor_curve_i = neighbor.index; - const float3 &neighbor_first_pos_cu = - positions_cu[curves_->offsets()[neighbor_curve_i]]; - const float3 neighbor_first_pos_su = curves_to_surface_mat_ * neighbor_first_pos_cu; - - BVHTreeNearest nearest; - nearest.dist_sq = FLT_MAX; - BLI_bvhtree_find_nearest(surface_bvh_.tree, - neighbor_first_pos_su, - &nearest, - surface_bvh_.nearest_callback, - &surface_bvh_); - const int neighbor_looptri_index = nearest.index; - const MLoopTri &neighbor_looptri = surface_looptris_[neighbor_looptri_index]; - - const float3 neighbor_bary_coord = compute_bary_coord_in_triangle( - *surface_, neighbor_looptri, nearest.co); - - const float3 neighbor_normal_su = compute_surface_point_normal( - surface_looptris_[neighbor_looptri_index], - neighbor_bary_coord, - corner_normals_su_); - const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ * - neighbor_normal_su); - - /* The rotation matrix used to transform relative coordinates of the neighbor curve - * to the new curve. */ - float normal_rotation_cu[3][3]; - rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu); - - const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i); - const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]]; - - /* Use a temporary #PolySpline, because that's the easiest way to resample an - * existing curve right now. Resampling is necessary if the length of the new curve - * does not match the length of the neighbors or the number of handle points is - * different. */ - PolySpline neighbor_spline; - neighbor_spline.resize(neighbor_points.size()); - neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points)); - neighbor_spline.mark_cache_invalid(); - - const float neighbor_length_cu = neighbor_spline.length(); - const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu); - - const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor; - for (const int j : IndexRange(points.size())) { - const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor( - j * resample_factor); - const float index_factor = lookup.evaluated_index + lookup.factor; - float3 p; - neighbor_spline.sample_with_index_factors<float3>( - neighbor_spline.positions(), {&index_factor, 1}, {&p, 1}); - const float3 relative_coord = p - neighbor_root_cu; - float3 rotated_relative_coord = relative_coord; - mul_m3_v3(normal_rotation_cu, rotated_relative_coord); - positions_cu[points[j]] += neighbor.weight * rotated_relative_coord; - } - } - } - }); - } }; void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc index 7e583773512..8c6ef34ef26 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc @@ -256,6 +256,55 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, return brush_3d; } +std::optional<CurvesBrush3D> sample_curves_surface_3d_brush( + const Depsgraph &depsgraph, + const ARegion ®ion, + const View3D &v3d, + const CurvesSculptTransforms &transforms, + const BVHTreeFromMesh &surface_bvh, + const float2 &brush_pos_re, + const float brush_radius_re) +{ + float3 brush_ray_start_wo, brush_ray_end_wo; + ED_view3d_win_to_segment_clipped( + &depsgraph, ®ion, &v3d, brush_pos_re, brush_ray_start_wo, brush_ray_end_wo, true); + const float3 brush_ray_start_su = transforms.world_to_surface * brush_ray_start_wo; + const float3 brush_ray_end_su = transforms.world_to_surface * brush_ray_end_wo; + + const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su); + + BVHTreeRayHit ray_hit; + ray_hit.dist = FLT_MAX; + ray_hit.index = -1; + BLI_bvhtree_ray_cast(surface_bvh.tree, + brush_ray_start_su, + brush_ray_direction_su, + 0.0f, + &ray_hit, + surface_bvh.raycast_callback, + const_cast<void *>(static_cast<const void *>(&surface_bvh))); + if (ray_hit.index == -1) { + return std::nullopt; + } + + float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo; + ED_view3d_win_to_segment_clipped(&depsgraph, + ®ion, + &v3d, + brush_pos_re + float2(brush_radius_re, 0), + brush_radius_ray_start_wo, + brush_radius_ray_end_wo, + true); + const float3 brush_radius_ray_start_cu = transforms.world_to_curves * brush_radius_ray_start_wo; + const float3 brush_radius_ray_end_cu = transforms.world_to_curves * brush_radius_ray_end_wo; + + const float3 brush_pos_su = ray_hit.co; + const float3 brush_pos_cu = transforms.surface_to_curves * brush_pos_su; + const float brush_radius_cu = dist_to_line_v3( + brush_pos_cu, brush_radius_ray_start_cu, brush_radius_ray_end_cu); + return CurvesBrush3D{brush_pos_cu, brush_radius_cu}; +} + Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry) { Vector<float4x4> matrices; @@ -284,6 +333,16 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr return matrices; } +float transform_brush_radius(const float4x4 &transform, + const float3 &brush_position, + const float old_radius) +{ + const float3 offset_position = brush_position + float3(old_radius, 0.0f, 0.0f); + const float3 new_position = transform * brush_position; + const float3 new_offset_position = transform * offset_position; + return math::distance(new_position, new_offset_position); +} + void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position) { /* Find the accumulated length of each point in the original curve, @@ -324,33 +383,18 @@ CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C) this->rv3d = CTX_wm_region_view3d(&C); } -float3 compute_surface_point_normal(const MLoopTri &looptri, - const float3 &bary_coord, - const Span<float3> corner_normals) -{ - const int l0 = looptri.tri[0]; - const int l1 = looptri.tri[1]; - const int l2 = looptri.tri[2]; - - const float3 &l0_normal = corner_normals[l0]; - const float3 &l1_normal = corner_normals[l1]; - const float3 &l2_normal = corner_normals[l2]; - - const float3 normal = math::normalize( - attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal)); - return normal; -} - -float3 compute_bary_coord_in_triangle(const Mesh &mesh, - const MLoopTri &looptri, - const float3 &position) +CurvesSculptTransforms::CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob) { - const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co; - const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co; - const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co; - float3 bary_coords; - interp_weights_tri_v3(bary_coords, v0, v1, v2, position); - return bary_coords; + this->curves_to_world = curves_ob.obmat; + this->world_to_curves = this->curves_to_world.inverted(); + + if (surface_ob != nullptr) { + this->surface_to_world = surface_ob->obmat; + this->world_to_surface = this->surface_to_world.inverted(); + this->surface_to_curves = this->world_to_curves * this->surface_to_world; + this->curves_to_surface = this->world_to_surface * this->curves_to_world; + this->surface_to_curves_normal = this->surface_to_curves.inverted().transposed(); + } } } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc index ae0a512c5ee..541bf9d8253 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc @@ -100,8 +100,7 @@ struct CombOperationExecutor { float2 brush_pos_re_; float2 brush_pos_diff_re_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; CombOperationExecutor(const bContext &C) : ctx_(C) { @@ -121,9 +120,6 @@ struct CombOperationExecutor { brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); - falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape); curves_id_ = static_cast<Curves *>(object_->data); @@ -132,6 +128,8 @@ struct CombOperationExecutor { return; } + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); + point_factors_ = get_point_selection(*curves_id_); curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); @@ -225,11 +223,11 @@ struct CombOperationExecutor { float3 new_position_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * old_pos_cu, + transforms_.curves_to_world * old_pos_cu, new_position_re, new_position_wo); const float3 new_position_cu = brush_transform * - (world_to_curves_mat_ * new_position_wo); + (transforms_.world_to_curves * new_position_wo); positions_cu[point_i] = new_position_cu; curve_changed = true; @@ -252,16 +250,16 @@ struct CombOperationExecutor { float3 brush_start_wo, brush_end_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_prev_re_, brush_start_wo); ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_end_wo); - const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo; - const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo; + const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo; + const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo; const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc index 6f12d539aa2..eab7dabcd22 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc @@ -76,8 +76,7 @@ struct DeleteOperationExecutor { float2 brush_pos_re_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; DeleteOperationExecutor(const bContext &C) : ctx_(C) { @@ -101,8 +100,7 @@ struct DeleteOperationExecutor { brush_pos_re_ = stroke_extension.mouse_position; - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( brush_->falloff_shape); @@ -199,10 +197,10 @@ struct DeleteOperationExecutor { float3 brush_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_wo); - const float3 brush_cu = world_to_curves_mat_ * brush_wo; + const float3 brush_cu = transforms_.world_to_curves * brush_wo; const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc index 3420659520b..cf893f09fc6 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc @@ -247,8 +247,7 @@ struct CurvesEffectOperationExecutor { eBrushFalloffShape falloff_shape_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; float2 brush_pos_start_re_; float2 brush_pos_end_re_; @@ -290,8 +289,7 @@ struct CurvesEffectOperationExecutor { falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape); - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); brush_pos_start_re_ = self.last_mouse_position_; brush_pos_end_re_ = stroke_extension.mouse_position; @@ -398,16 +396,16 @@ struct CurvesEffectOperationExecutor { float3 brush_start_pos_wo, brush_end_pos_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * closest_on_segment_cu, + transforms_.curves_to_world * closest_on_segment_cu, brush_pos_start_re_, brush_start_pos_wo); ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * closest_on_segment_cu, + transforms_.curves_to_world * closest_on_segment_cu, brush_pos_end_re_, brush_end_pos_wo); - const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo; - const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo; + const float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo; + const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo; const float move_distance_cu = weight * math::distance(brush_start_pos_cu, brush_end_pos_cu); @@ -430,16 +428,16 @@ struct CurvesEffectOperationExecutor { float3 brush_pos_start_wo, brush_pos_end_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_start_re_, brush_pos_start_wo); ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_end_re_, brush_pos_end_wo); - const float3 brush_pos_start_cu = world_to_curves_mat_ * brush_pos_start_wo; - const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo; + const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo; + const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo; const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu; const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu); const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh index 5c926b1a740..ad3871bee45 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh @@ -21,6 +21,7 @@ struct View3D; struct Object; struct Brush; struct Scene; +struct BVHTreeFromMesh; namespace blender::ed::sculpt_paint { @@ -60,6 +61,13 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation( const BrushStrokeMode brush_mode, const bContext &C); std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation( const BrushStrokeMode brush_mode, const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode, + const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation(); +std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation(); +std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation( + const BrushStrokeMode brush_mode, const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation(); struct CurvesBrush3D { float3 position_cu; @@ -97,14 +105,6 @@ IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_i void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position); -float3 compute_surface_point_normal(const MLoopTri &looptri, - const float3 &bary_coord, - const Span<float3> corner_normals); - -float3 compute_bary_coord_in_triangle(const Mesh &mesh, - const MLoopTri &looptri, - const float3 &position); - class CurvesSculptCommonContext { public: const Depsgraph *depsgraph = nullptr; @@ -116,4 +116,30 @@ class CurvesSculptCommonContext { CurvesSculptCommonContext(const bContext &C); }; +struct CurvesSculptTransforms { + float4x4 curves_to_world; + float4x4 curves_to_surface; + float4x4 world_to_curves; + float4x4 world_to_surface; + float4x4 surface_to_world; + float4x4 surface_to_curves; + float4x4 surface_to_curves_normal; + + CurvesSculptTransforms() = default; + CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob); +}; + +std::optional<CurvesBrush3D> sample_curves_surface_3d_brush( + const Depsgraph &depsgraph, + const ARegion ®ion, + const View3D &v3d, + const CurvesSculptTransforms &transforms, + const BVHTreeFromMesh &surface_bvh, + const float2 &brush_pos_re, + const float brush_radius_re); + +float transform_brush_radius(const float4x4 &transform, + const float3 &brush_position, + const float old_radius); + } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc index 69615a3bfb4..b40aebcaaf1 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc @@ -66,8 +66,7 @@ struct SelectionPaintOperationExecutor { float2 brush_pos_re_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; SelectionPaintOperationExecutor(const bContext &C) : ctx_(C) { @@ -105,8 +104,7 @@ struct SelectionPaintOperationExecutor { } } - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( brush_->falloff_shape); @@ -201,10 +199,10 @@ struct SelectionPaintOperationExecutor { float3 brush_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_wo); - const float3 brush_cu = world_to_curves_mat_ * brush_wo; + const float3 brush_cu = transforms_.world_to_curves * brush_wo; const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); @@ -309,10 +307,10 @@ struct SelectionPaintOperationExecutor { float3 brush_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_wo); - const float3 brush_cu = world_to_curves_mat_ * brush_wo; + const float3 brush_cu = transforms_.world_to_curves * brush_wo; const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc index e1aecabdcc7..b63e5a7756b 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc @@ -89,8 +89,7 @@ struct SnakeHookOperatorExecutor { Vector<int64_t> selected_curve_indices_; IndexMask curve_selection_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; float2 brush_pos_prev_re_; float2 brush_pos_re_; @@ -118,15 +117,14 @@ struct SnakeHookOperatorExecutor { falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape); - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); - curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); if (curves_->curves_num() == 0) { return; } + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); + curve_factors_ = get_curves_selection(*curves_id_); curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); @@ -210,10 +208,11 @@ struct SnakeHookOperatorExecutor { float3 new_position_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * old_pos_cu, + transforms_.curves_to_world * old_pos_cu, new_position_re, new_position_wo); - const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo); + const float3 new_position_cu = brush_transform * + (transforms_.world_to_curves * new_position_wo); move_last_point_and_resample(positions_cu.slice(points), new_position_cu); } @@ -228,16 +227,16 @@ struct SnakeHookOperatorExecutor { float3 brush_start_wo, brush_end_wo; ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_prev_re_, brush_start_wo); ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_end_wo); - const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo; - const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo; + const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo; + const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo; const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc index a2e1adff50a..6a47aceb2b0 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc @@ -11,6 +11,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BLI_array.hh" #include "BLI_math_base.h" #include "BLI_math_color.h" @@ -30,6 +31,8 @@ #include "paint_intern.h" /* own include */ +using blender::Array; + /* -------------------------------------------------------------------- */ /** \name Internal Utility Functions * \{ */ @@ -45,7 +48,7 @@ static bool vertex_weight_paint_mode_poll(bContext *C) static void tag_object_after_update(Object *object) { BLI_assert(object->type == OB_MESH); - Mesh *mesh = object->data; + Mesh *mesh = static_cast<Mesh *>(object->data); DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE); /* NOTE: Original mesh is used for display, so tag it directly here. */ BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); @@ -63,7 +66,8 @@ static bool vertex_paint_from_weight(Object *ob) const MPoly *mp; int vgroup_active; - if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) { + if (((me = BKE_mesh_from_object(ob)) == nullptr || + (ED_mesh_color_ensure(me, nullptr)) == false)) { return false; } @@ -128,14 +132,13 @@ static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag) { const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; const MPoly *mp; - int(*scol)[4]; bool has_shared = false; - if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) { + if (me->mloopcol == nullptr || me->totvert == 0 || me->totpoly == 0) { return; } - scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol"); + int(*scol)[4] = static_cast<int(*)[4]>(MEM_callocN(sizeof(int) * me->totvert * 5, "scol")); int i; for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { @@ -185,16 +188,15 @@ static bool vertex_color_smooth(Object *ob) const MPoly *mp; int i, j; - bool *mlooptag; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { + if (((me = BKE_mesh_from_object(ob)) == nullptr) || + (ED_mesh_color_ensure(me, nullptr) == false)) { return false; } const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); + Array<bool> loop_tag(me->totloop, false); /* simply tag loops of selected faces */ mp = me->mpoly; @@ -208,7 +210,7 @@ static bool vertex_color_smooth(Object *ob) j = 0; do { if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) { - mlooptag[mp->loopstart + j] = true; + loop_tag[mp->loopstart + j] = true; } ml++; j++; @@ -218,9 +220,7 @@ static bool vertex_color_smooth(Object *ob) /* remove stale me->mcol, will be added later */ BKE_mesh_tessface_clear(me); - vertex_color_smooth_looptag(me, mlooptag); - - MEM_freeN(mlooptag); + vertex_color_smooth_looptag(me, loop_tag.data()); tag_object_after_update(ob); @@ -268,7 +268,8 @@ static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) { - const struct VPaintTx_BrightContrastData *data = user_data; + const VPaintTx_BrightContrastData *data = static_cast<const VPaintTx_BrightContrastData *>( + user_data); for (int i = 0; i < 3; i++) { r_col[i] = data->gain * col[i] + data->offset; @@ -302,10 +303,9 @@ static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) } } - const struct VPaintTx_BrightContrastData user_data = { - .gain = gain, - .offset = offset, - }; + VPaintTx_BrightContrastData user_data{}; + user_data.gain = gain; + user_data.offset = offset; if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); @@ -345,7 +345,7 @@ struct VPaintTx_HueSatData { static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) { - const struct VPaintTx_HueSatData *data = user_data; + const VPaintTx_HueSatData *data = static_cast<const VPaintTx_HueSatData *>(user_data); float hsv[3]; rgb_to_hsv_v(col, hsv); @@ -366,11 +366,10 @@ static int vertex_color_hsv_exec(bContext *C, wmOperator *op) { Object *obact = CTX_data_active_object(C); - const struct VPaintTx_HueSatData user_data = { - .hue = RNA_float_get(op->ptr, "h"), - .sat = RNA_float_get(op->ptr, "s"), - .val = RNA_float_get(op->ptr, "v"), - }; + VPaintTx_HueSatData user_data{}; + user_data.hue = RNA_float_get(op->ptr, "h"); + user_data.sat = RNA_float_get(op->ptr, "s"); + user_data.val = RNA_float_get(op->ptr, "v"); if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); @@ -410,7 +409,7 @@ static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obact = CTX_data_active_object(C); - if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { + if (ED_vpaint_color_transform(obact, vpaint_tx_invert, nullptr)) { WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); return OPERATOR_FINISHED; } @@ -439,7 +438,7 @@ struct VPaintTx_LevelsData { static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) { - const struct VPaintTx_LevelsData *data = user_data; + const VPaintTx_LevelsData *data = static_cast<const VPaintTx_LevelsData *>(user_data); for (int i = 0; i < 3; i++) { r_col[i] = data->gain * (col[i] + data->offset); } @@ -449,10 +448,9 @@ static int vertex_color_levels_exec(bContext *C, wmOperator *op) { Object *obact = CTX_data_active_object(C); - const struct VPaintTx_LevelsData user_data = { - .gain = RNA_float_get(op->ptr, "gain"), - .offset = RNA_float_get(op->ptr, "offset"), - }; + VPaintTx_LevelsData user_data{}; + user_data.gain = RNA_float_get(op->ptr, "gain"); + user_data.offset = RNA_float_get(op->ptr, "offset"); if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); |