diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/curves_sculpt_slide.cc')
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_slide.cc | 485 |
1 files changed, 338 insertions, 147 deletions
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc index aabe6fd93e4..1108f5c72a9 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc @@ -4,6 +4,7 @@ #include "curves_sculpt_intern.hh" +#include "BLI_float3x3.hh" #include "BLI_float4x4.hh" #include "BLI_vector.hh" @@ -20,14 +21,16 @@ #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" +#include "BKE_modifier.h" +#include "BKE_object.h" #include "BKE_paint.h" +#include "BKE_report.h" #include "DNA_brush_enums.h" #include "DNA_brush_types.h" #include "DNA_curves_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -38,13 +41,27 @@ #include "WM_api.h" +#include "DEG_depsgraph_query.h" + +#include "GEO_add_curves_on_mesh.hh" +#include "GEO_reverse_uv_sampler.hh" + +#include "BLT_translation.h" + namespace blender::ed::sculpt_paint { +using geometry::ReverseUVSampler; + struct SlideCurveInfo { /** Index of the curve to slide. */ int curve_i; /** A weight based on the initial distance to the brush. */ float radius_falloff; + /** + * Normal of the surface where the curve was attached. This is used to rotate the curve if it is + * moved to a place with a different normal. + */ + float3 initial_normal_cu; }; struct SlideInfo { @@ -55,10 +72,13 @@ struct SlideInfo { class SlideOperation : public CurvesSculptStrokeOperation { private: - /** Last mouse position. */ - float2 brush_pos_last_re_; + float2 initial_brush_pos_re_; /** Information about which curves to slide. This is initialized when the brush starts. */ Vector<SlideInfo> slide_info_; + /** Positions of all curve points at the start of sliding. */ + Array<float3> initial_positions_cu_; + /** Deformed positions of all curve points at the start of sliding. */ + Array<float3> initial_deformed_positions_cu_; friend struct SlideOperationExecutor; @@ -80,27 +100,33 @@ struct SlideOperationExecutor { float brush_radius_factor_; float brush_strength_; - 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_ = nullptr; - Mesh *surface_ = nullptr; - Span<MLoopTri> surface_looptris_; - VArraySpan<float2> surface_uv_map_; + Object *surface_ob_orig_ = nullptr; + Mesh *surface_orig_ = nullptr; + Span<MLoopTri> surface_looptris_orig_; + VArraySpan<float2> surface_uv_map_orig_; + Span<float3> corner_normals_orig_su_; + + Object *surface_ob_eval_ = nullptr; + Mesh *surface_eval_ = nullptr; + Span<MVert> surface_verts_eval_; + Span<MLoop> surface_loops_eval_; + Span<MLoopTri> surface_looptris_eval_; + VArraySpan<float2> surface_uv_map_eval_; + BVHTreeFromMesh surface_bvh_eval_; VArray<float> curve_factors_; - VArray<float> point_factors_; Vector<int64_t> selected_curve_indices_; IndexMask curve_selection_; - float2 brush_pos_prev_re_; float2 brush_pos_re_; - float2 brush_pos_diff_re_; CurvesSurfaceTransforms transforms_; - BVHTreeFromMesh surface_bvh_; + std::atomic<bool> found_invalid_uv_mapping_{false}; SlideOperationExecutor(const bContext &C) : ctx_(C) { @@ -111,15 +137,27 @@ struct SlideOperationExecutor { UNUSED_VARS(C, stroke_extension); self_ = &self; - object_ = CTX_data_active_object(&C); - curves_id_ = static_cast<Curves *>(object_->data); - curves_ = &CurvesGeometry::wrap(curves_id_->geometry); - if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) { + curves_ob_orig_ = CTX_data_active_object(&C); + curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data); + curves_orig_ = &CurvesGeometry::wrap(curves_id_orig_->geometry); + if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) { + report_missing_surface(stroke_extension.reports); + return; + } + if (curves_orig_->curves_num() == 0) { + return; + } + if (curves_id_orig_->surface_uv_map == nullptr) { + report_missing_uv_map_on_original_surface(stroke_extension.reports); return; } - if (curves_->curves_num() == 0) { + if (curves_orig_->surface_uv_coords().is_empty()) { + BKE_report(stroke_extension.reports, + RPT_WARNING, + TIP_("Curves do not have surface attachment information")); return; } + const StringRefNull uv_map_name = curves_id_orig_->surface_uv_map; curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); @@ -127,169 +165,322 @@ struct SlideOperationExecutor { brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); - curve_factors_ = get_curves_selection(*curves_id_); - point_factors_ = get_point_selection(*curves_id_); - curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + curve_factors_ = get_curves_selection(*curves_id_orig_); + curve_selection_ = retrieve_selected_curves(*curves_id_orig_, selected_curve_indices_); - brush_pos_prev_re_ = self_->brush_pos_last_re_; brush_pos_re_ = stroke_extension.mouse_position; - brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_; - BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = brush_pos_re_; }); - - transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface); - surface_ob_ = curves_id_->surface; - surface_ = static_cast<Mesh *>(surface_ob_->data); + transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface); - BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); - BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); }); - - 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<Mesh *>(surface_ob_orig_->data); + if (surface_orig_->totpoly == 0) { + report_empty_original_surface(stroke_extension.reports); + return; + } + surface_looptris_orig_ = {BKE_mesh_runtime_looptri_ensure(surface_orig_), + BKE_mesh_runtime_looptri_len(surface_orig_)}; + surface_uv_map_orig_ = surface_orig_->attributes().lookup<float2>(uv_map_name, + ATTR_DOMAIN_CORNER); + if (surface_uv_map_orig_.is_empty()) { + report_missing_uv_map_on_original_surface(stroke_extension.reports); + return; + } + if (!CustomData_has_layer(&surface_orig_->ldata, CD_NORMAL)) { + BKE_mesh_calc_normals_split(surface_orig_); + } + corner_normals_orig_su_ = { + reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig_->ldata, CD_NORMAL)), + surface_orig_->totloop}; - if (curves_id_->surface_uv_map != nullptr) { - const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_); - surface_uv_map_ = surface_attributes.lookup<float2>(curves_id_->surface_uv_map, - ATTR_DOMAIN_CORNER); + 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 (surface_eval_ == nullptr) { + return; + } + if (surface_eval_->totpoly == 0) { + report_empty_evaluated_surface(stroke_extension.reports); + return; + } + surface_looptris_eval_ = {BKE_mesh_runtime_looptri_ensure(surface_eval_), + BKE_mesh_runtime_looptri_len(surface_eval_)}; + surface_verts_eval_ = surface_eval_->verts(); + surface_loops_eval_ = surface_eval_->loops(); + surface_uv_map_eval_ = surface_eval_->attributes().lookup<float2>(uv_map_name, + ATTR_DOMAIN_CORNER); + if (surface_uv_map_eval_.is_empty()) { + report_missing_uv_map_on_evaluated_surface(stroke_extension.reports); + return; } + BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2); + BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); }); if (stroke_extension.is_first) { - const Vector<float4x4> brush_transforms = get_symmetry_brush_transforms( - eCurvesSymmetryType(curves_id_->symmetry)); - for (const float4x4 &brush_transform : brush_transforms) { - this->detect_curves_to_slide(brush_transform); - } + self_->initial_brush_pos_re_ = brush_pos_re_; + /* Remember original and deformed positions of all points. Otherwise this information is lost + * when sliding starts, but it's still used. */ + const bke::crazyspace::GeometryDeformation deformation = + bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_); + self_->initial_positions_cu_ = curves_orig_->positions(); + self_->initial_deformed_positions_cu_ = deformation.positions; + + /* First find all curves to slide. When the mouse moves, only those curves will be moved. */ + this->find_curves_to_slide_with_symmetry(); return; } - this->slide_projected(); + this->slide_with_symmetry(); - curves_->tag_positions_changed(); - DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); + if (found_invalid_uv_mapping_) { + BKE_report( + stroke_extension.reports, RPT_WARNING, TIP_("UV map or surface attachment is invalid")); + } + + curves_orig_->tag_positions_changed(); + 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 detect_curves_to_slide(const float4x4 &brush_transform) + void find_curves_to_slide_with_symmetry() { - const float4x4 brush_transform_inv = brush_transform.inverted(); - + const Vector<float4x4> brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_orig_->symmetry)); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; - const float brush_radius_sq_re = pow2f(brush_radius_re); - - const Span<float3> positions_cu = curves_->positions(); - - float4x4 projection; - ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + transforms_, + surface_bvh_eval_, + brush_pos_re_, + brush_radius_re); + if (!brush_3d.has_value()) { + return; + } + const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_, surface_looptris_orig_}; + for (const float4x4 &brush_transform : brush_transforms) { + self_->slide_info_.append_as(); + SlideInfo &slide_info = self_->slide_info_.last(); + slide_info.brush_transform = brush_transform; + this->find_curves_to_slide(brush_transform * brush_3d->position_cu, + brush_3d->radius_cu, + reverse_uv_sampler_orig, + slide_info.curves_to_slide); + } + } - self_->slide_info_.append({brush_transform}); - Vector<SlideCurveInfo> &curves_to_slide = self_->slide_info_.last().curves_to_slide; + void find_curves_to_slide(const float3 &brush_pos_cu, + const float brush_radius_cu, + const ReverseUVSampler &reverse_uv_sampler_orig, + Vector<SlideCurveInfo> &r_curves_to_slide) + { + const Span<float2> surface_uv_coords = curves_orig_->surface_uv_coords(); + const float brush_radius_sq_cu = pow2f(brush_radius_cu); - /* Find curves in brush radius that should be moved. */ + const Span<int> offsets = curves_orig_->offsets(); for (const int curve_i : curve_selection_) { - const int first_point_i = curves_->offsets()[curve_i]; - const float3 &first_pos_cu = brush_transform_inv * positions_cu[first_point_i]; - - float2 first_pos_re; - ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, first_pos_re, projection.values); - - const float dist_to_brush_sq_re = math::distance_squared(first_pos_re, brush_pos_re_); - if (dist_to_brush_sq_re > brush_radius_sq_re) { + const int first_point_i = offsets[curve_i]; + const float3 old_pos_cu = self_->initial_deformed_positions_cu_[first_point_i]; + const float dist_to_brush_sq_cu = math::distance_squared(old_pos_cu, brush_pos_cu); + if (dist_to_brush_sq_cu > brush_radius_sq_cu) { + /* Root point is too far away from curve center. */ continue; } - const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re); + const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu); const float radius_falloff = BKE_brush_curve_strength( - brush_, dist_to_brush_re, brush_radius_re); - curves_to_slide.append({curve_i, radius_falloff}); + brush_, dist_to_brush_cu, brush_radius_cu); + + const float2 uv = surface_uv_coords[curve_i]; + ReverseUVSampler::Result result = reverse_uv_sampler_orig.sample(uv); + if (result.type != ReverseUVSampler::ResultType::Ok) { + /* The curve does not have a valid surface attachment. */ + found_invalid_uv_mapping_.store(true); + continue; + } + /* Compute the normal at the initial surface position. */ + const float3 normal_cu = math::normalize( + transforms_.surface_to_curves_normal * + geometry::compute_surface_point_normal( + *result.looptri, result.bary_weights, corner_normals_orig_su_)); + + r_curves_to_slide.append({curve_i, radius_falloff, normal_cu}); } } - void slide_projected() + void slide_with_symmetry() { - MutableSpan<float3> positions_cu = curves_->positions_for_write(); - - MutableSpan<float2> surface_uv_coords; - if (!surface_uv_map_.is_empty()) { - surface_uv_coords = curves_->surface_uv_coords_for_write(); + const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_, surface_looptris_orig_}; + for (const SlideInfo &slide_info : self_->slide_info_) { + this->slide(slide_info.curves_to_slide, reverse_uv_sampler_orig, slide_info.brush_transform); } + } - float4x4 projection; - ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + void slide(const Span<SlideCurveInfo> slide_curves, + const ReverseUVSampler &reverse_uv_sampler_orig, + const float4x4 &brush_transform) + { + const float4x4 brush_transform_inv = brush_transform.inverted(); - for (const SlideInfo &slide_info : self_->slide_info_) { - const float4x4 &brush_transform = slide_info.brush_transform; - const float4x4 brush_transform_inv = brush_transform.inverted(); - const Span<SlideCurveInfo> curves_to_slide = slide_info.curves_to_slide; - - threading::parallel_for(curves_to_slide.index_range(), 256, [&](const IndexRange range) { - for (const SlideCurveInfo &curve_slide_info : curves_to_slide.slice(range)) { - const int curve_i = curve_slide_info.curve_i; - const IndexRange points = curves_->points_for_curve(curve_i); - const int first_point_i = points.first(); - const float3 old_first_pos_cu = brush_transform_inv * positions_cu[first_point_i]; - - float2 old_first_pos_re; - ED_view3d_project_float_v2_m4( - ctx_.region, old_first_pos_cu, old_first_pos_re, projection.values); - const float first_point_weight = brush_strength_ * curve_slide_info.radius_falloff; - - /* Slide root position in region space and then project it back onto the surface. */ - const float2 new_first_pos_re = old_first_pos_re + - first_point_weight * brush_pos_diff_re_; - - float3 ray_start_wo, ray_end_wo; - ED_view3d_win_to_segment_clipped(ctx_.depsgraph, - ctx_.region, - ctx_.v3d, - new_first_pos_re, - ray_start_wo, - ray_end_wo, - true); - const float3 ray_start_su = transforms_.world_to_surface * ray_start_wo; - const float3 ray_end_su = transforms_.world_to_surface * ray_end_wo; - - const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su); - BVHTreeRayHit hit; - hit.dist = FLT_MAX; - hit.index = -1; - BLI_bvhtree_ray_cast(surface_bvh_.tree, - ray_start_su, - ray_direction_su, - 0.0f, - &hit, - surface_bvh_.raycast_callback, - &surface_bvh_); - if (hit.index == -1) { - continue; - } + const Span<MVert> verts_orig_su = surface_orig_->verts(); + const Span<MLoop> loops_orig = surface_orig_->loops(); - const int looptri_index = hit.index; - const float3 attached_pos_su = hit.co; + MutableSpan<float3> positions_orig_cu = curves_orig_->positions_for_write(); + MutableSpan<float2> surface_uv_coords = curves_orig_->surface_uv_coords_for_write(); - const float3 attached_pos_cu = transforms_.surface_to_curves * attached_pos_su; - const float3 pos_offset_cu = brush_transform * (attached_pos_cu - old_first_pos_cu); + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values); + + const float2 brush_pos_diff_re = brush_pos_re_ - self_->initial_brush_pos_re_; + + /* The brush transformation has to be applied in curves space. */ + const float4x4 world_to_surface_with_symmetry_mat = transforms_.curves_to_surface * + brush_transform * + transforms_.world_to_curves; + + threading::parallel_for(slide_curves.index_range(), 256, [&](const IndexRange range) { + for (const SlideCurveInfo &slide_curve_info : slide_curves.slice(range)) { + const int curve_i = slide_curve_info.curve_i; + const IndexRange points = curves_orig_->points_for_curve(curve_i); + const int first_point_i = points[0]; + + const float3 old_first_pos_eval_cu = self_->initial_deformed_positions_cu_[first_point_i]; + const float3 old_first_symm_pos_eval_cu = brush_transform_inv * old_first_pos_eval_cu; + const float3 old_first_pos_eval_su = transforms_.curves_to_surface * old_first_pos_eval_cu; + + float2 old_first_symm_pos_eval_re; + ED_view3d_project_float_v2_m4(ctx_.region, + old_first_symm_pos_eval_cu, + old_first_symm_pos_eval_re, + projection.values); + + const float radius_falloff = slide_curve_info.radius_falloff; + const float curve_weight = brush_strength_ * radius_falloff * curve_factors_[curve_i]; + const float2 new_first_symm_pos_eval_re = old_first_symm_pos_eval_re + + curve_weight * brush_pos_diff_re; + + /* Compute the ray that will be used to find the new position on the surface. */ + float3 ray_start_wo, ray_end_wo; + ED_view3d_win_to_segment_clipped(ctx_.depsgraph, + ctx_.region, + ctx_.v3d, + new_first_symm_pos_eval_re, + ray_start_wo, + ray_end_wo, + true); + const float3 ray_start_su = world_to_surface_with_symmetry_mat * ray_start_wo; + const float3 ray_end_su = world_to_surface_with_symmetry_mat * ray_end_wo; + const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su); + + /* Find the ray hit that is closest to the initial curve root position. */ + int looptri_index_eval; + float3 hit_pos_eval_su; + if (!this->find_closest_ray_hit(ray_start_su, + ray_direction_su, + old_first_pos_eval_su, + looptri_index_eval, + hit_pos_eval_su)) { + continue; + } - /* Update positions. The first point doesn't have an additional weight here, because then - * it wouldn't be attached to the surface anymore. */ - positions_cu[first_point_i] += pos_offset_cu; - for (const int point_i : points.drop_front(1)) { - const float weight = point_factors_[point_i]; - positions_cu[point_i] += weight * pos_offset_cu; - } + /* Compute the uv of the new surface position on the evaluated mesh. */ + const MLoopTri &looptri_eval = surface_looptris_eval_[looptri_index_eval]; + const float3 bary_weights_eval = bke::mesh_surface_sample::compute_bary_coord_in_triangle( + surface_verts_eval_, surface_loops_eval_, looptri_eval, hit_pos_eval_su); + const float2 uv = attribute_math::mix3(bary_weights_eval, + surface_uv_map_eval_[looptri_eval.tri[0]], + surface_uv_map_eval_[looptri_eval.tri[1]], + surface_uv_map_eval_[looptri_eval.tri[2]]); + + /* Try to find the same uv on the original surface. */ + const ReverseUVSampler::Result result = reverse_uv_sampler_orig.sample(uv); + if (result.type != ReverseUVSampler::ResultType::Ok) { + found_invalid_uv_mapping_.store(true); + continue; + } + const MLoopTri &looptri_orig = *result.looptri; + const float3 &bary_weights_orig = result.bary_weights; + + /* Gather old and new surface normal. */ + const float3 &initial_normal_cu = slide_curve_info.initial_normal_cu; + const float3 new_normal_cu = math::normalize( + transforms_.surface_to_curves_normal * + geometry::compute_surface_point_normal( + *result.looptri, result.bary_weights, corner_normals_orig_su_)); + + /* Gather old and new surface position. */ + const float3 old_first_pos_orig_cu = self_->initial_positions_cu_[first_point_i]; + const float3 new_first_pos_orig_cu = + transforms_.surface_to_curves * + attribute_math::mix3<float3>(bary_weights_orig, + verts_orig_su[loops_orig[looptri_orig.tri[0]].v].co, + verts_orig_su[loops_orig[looptri_orig.tri[1]].v].co, + verts_orig_su[loops_orig[looptri_orig.tri[2]].v].co); + + /* Actually transform curve points. */ + const float4x4 slide_transform = this->get_slide_transform( + old_first_pos_orig_cu, new_first_pos_orig_cu, initial_normal_cu, new_normal_cu); + for (const int point_i : points) { + positions_orig_cu[point_i] = slide_transform * self_->initial_positions_cu_[point_i]; + } + surface_uv_coords[curve_i] = uv; + } + }); + } - /* Update surface attachment information if necessary. */ - if (!surface_uv_map_.is_empty()) { - const MLoopTri &looptri = surface_looptris_[looptri_index]; - const float3 bary_coord = bke::mesh_surface_sample::compute_bary_coord_in_triangle( - *surface_, looptri, attached_pos_su); - 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 float2 uv = attribute_math::mix3(bary_coord, uv0, uv1, uv2); - surface_uv_coords[curve_i] = uv; + bool find_closest_ray_hit(const float3 &ray_start_su, + const float3 &ray_direction_su, + const float3 &point_su, + int &r_looptri_index, + float3 &r_hit_pos) + { + float best_dist_sq_su = FLT_MAX; + int best_looptri_index_eval; + float3 best_hit_pos_su; + BLI_bvhtree_ray_cast_all_cpp( + *surface_bvh_eval_.tree, + ray_start_su, + ray_direction_su, + 0.0f, + FLT_MAX, + [&](const int looptri_index, const BVHTreeRay &ray, BVHTreeRayHit &hit) { + surface_bvh_eval_.raycast_callback(&surface_bvh_eval_, looptri_index, &ray, &hit); + if (hit.index < 0) { + return; } - } - }); + const float3 &hit_pos_su = hit.co; + const float dist_sq_su = math::distance_squared(hit_pos_su, point_su); + if (dist_sq_su < best_dist_sq_su) { + best_dist_sq_su = dist_sq_su; + best_hit_pos_su = hit_pos_su; + best_looptri_index_eval = hit.index; + } + }); + + if (best_dist_sq_su == FLT_MAX) { + return false; } + r_looptri_index = best_looptri_index_eval; + r_hit_pos = best_hit_pos_su; + return true; + } + + float4x4 get_slide_transform(const float3 &old_root_pos, + const float3 &new_root_pos, + const float3 &old_normal, + const float3 &new_normal) + { + float3x3 rotation_3x3; + rotation_between_vecs_to_mat3(rotation_3x3.values, old_normal, new_normal); + float4x4 rotation_4x4; + copy_m4_m3(rotation_4x4.values, rotation_3x3.values); + + float4x4 transform = float4x4::identity(); + sub_v3_v3(transform.values[3], old_root_pos); + mul_m4_m4_pre(transform.values, rotation_4x4.values); + add_v3_v3(transform.values[3], new_root_pos); + return transform; } }; |