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 --- source/blender/geometry/GEO_add_curves_on_mesh.hh | 20 ++-- .../blender/geometry/intern/add_curves_on_mesh.cc | 104 ++++++++++----------- .../blender/geometry/intern/realize_instances.cc | 17 +++- 3 files changed, 77 insertions(+), 64 deletions(-) (limited to 'source/blender/geometry') diff --git a/source/blender/geometry/GEO_add_curves_on_mesh.hh b/source/blender/geometry/GEO_add_curves_on_mesh.hh index cf60a8e8ace..68c8dc5b76b 100644 --- a/source/blender/geometry/GEO_add_curves_on_mesh.hh +++ b/source/blender/geometry/GEO_add_curves_on_mesh.hh @@ -13,13 +13,13 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "GEO_reverse_uv_sampler.hh" + namespace blender::geometry { struct AddCurvesOnMeshInputs { - /** Information about the root points where new curves should be generated. */ - Span root_positions_cu; - Span bary_coords; - Span looptri_indices; + /** UV Coordinates at which the new curves should be added. */ + Span uvs; /** Determines shape of new curves. */ bool interpolate_length = false; @@ -30,14 +30,10 @@ struct AddCurvesOnMeshInputs { /** Information about the surface that the new curves are attached to. */ const Mesh *surface = nullptr; - BVHTreeFromMesh *surface_bvh = nullptr; - Span surface_looptris; - Span surface_uv_map; + const ReverseUVSampler *reverse_uv_sampler = nullptr; Span corner_normals_su; - /** Transformation matrices. */ - float4x4 curves_to_surface_mat; - float4x4 surface_to_curves_normal_mat; + bke::CurvesSurfaceTransforms *transforms = nullptr; /** * KD-Tree that contains the root points of existing curves. This is only necessary when @@ -51,4 +47,8 @@ struct AddCurvesOnMeshInputs { */ void add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs); +float3 compute_surface_point_normal(const MLoopTri &looptri, + const float3 &bary_coord, + const Span corner_normals); + } // namespace blender::geometry diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc index e54e2bdd3b0..aa04cedb5c5 100644 --- a/source/blender/geometry/intern/add_curves_on_mesh.cc +++ b/source/blender/geometry/intern/add_curves_on_mesh.cc @@ -6,6 +6,7 @@ #include "BKE_mesh_sample.hh" #include "GEO_add_curves_on_mesh.hh" +#include "GEO_reverse_uv_sampler.hh" /** * The code below uses a suffix naming convention to indicate the coordinate space: @@ -27,9 +28,9 @@ struct NeighborCurve { static constexpr int max_neighbors = 5; using NeighborCurves = Vector; -static float3 compute_surface_point_normal(const MLoopTri &looptri, - const float3 &bary_coord, - const Span corner_normals) +float3 compute_surface_point_normal(const MLoopTri &looptri, + const float3 &bary_coord, + const Span corner_normals) { const int l0 = looptri.tri[0]; const int l1 = looptri.tri[1]; @@ -136,16 +137,15 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves, const int old_curves_num, const Span new_lengths_cu, const Span new_normals_su, - const float4x4 &surface_to_curves_normal_mat, - const float4x4 &curves_to_surface_mat, - const BVHTreeFromMesh &surface_bvh, - const Span surface_looptris, - const Mesh &surface, + const bke::CurvesSurfaceTransforms &transforms, + const ReverseUVSampler &reverse_uv_sampler, const Span corner_normals_su) { MutableSpan positions_cu = curves.positions_for_write(); const int added_curves_num = root_positions_cu.size(); + const Span uv_coords = curves.surface_uv_coords(); + threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) { for (const int added_curve_i : range) { const NeighborCurves &neighbors = neighbors_per_curve[added_curve_i]; @@ -154,7 +154,7 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves, const float length_cu = new_lengths_cu[added_curve_i]; const float3 &normal_su = new_normals_su[added_curve_i]; - const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su); + const float3 normal_cu = math::normalize(transforms.surface_to_curves_normal * normal_su); const float3 &root_cu = root_positions_cu[added_curve_i]; @@ -169,26 +169,15 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves, for (const NeighborCurve &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, - const_cast(&surface_bvh)); - const int neighbor_looptri_index = nearest.index; - const MLoopTri &neighbor_looptri = surface_looptris[neighbor_looptri_index]; - - const float3 neighbor_bary_coord = - bke::mesh_surface_sample::compute_bary_coord_in_triangle( - surface, neighbor_looptri, nearest.co); + const float2 neighbor_uv = uv_coords[neighbor_curve_i]; + const ReverseUVSampler::Result result = reverse_uv_sampler.sample(neighbor_uv); + if (result.type != ReverseUVSampler::ResultType::Ok) { + continue; + } 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 * + *result.looptri, result.bary_weights, corner_normals_su); + const float3 neighbor_normal_cu = math::normalize(transforms.surface_to_curves_normal * neighbor_normal_su); /* The rotation matrix used to transform relative coordinates of the neighbor curve @@ -245,13 +234,37 @@ void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inp const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count || inputs.interpolate_shape; + Vector root_positions_cu; + Vector bary_coords; + Vector looptris; + Vector used_uvs; + + /* Find faces that the passed in uvs belong to. */ + for (const int i : inputs.uvs.index_range()) { + const float2 &uv = inputs.uvs[i]; + const ReverseUVSampler::Result result = inputs.reverse_uv_sampler->sample(uv); + if (result.type != ReverseUVSampler::ResultType::Ok) { + continue; + } + const MLoopTri &looptri = *result.looptri; + bary_coords.append(result.bary_weights); + looptris.append(&looptri); + const float3 root_position_su = attribute_math::mix3( + result.bary_weights, + inputs.surface->mvert[inputs.surface->mloop[looptri.tri[0]].v].co, + inputs.surface->mvert[inputs.surface->mloop[looptri.tri[1]].v].co, + inputs.surface->mvert[inputs.surface->mloop[looptri.tri[2]].v].co); + root_positions_cu.append(inputs.transforms->surface_to_curves * root_position_su); + used_uvs.append(uv); + } + Array neighbors_per_curve; if (use_interpolation) { BLI_assert(inputs.old_roots_kdtree != nullptr); - neighbors_per_curve = find_curve_neighbors(inputs.root_positions_cu, *inputs.old_roots_kdtree); + neighbors_per_curve = find_curve_neighbors(root_positions_cu, *inputs.old_roots_kdtree); } - const int added_curves_num = inputs.root_positions_cu.size(); + const int added_curves_num = root_positions_cu.size(); const int old_points_num = curves.points_num(); const int old_curves_num = curves.curves_num(); const int new_curves_num = old_curves_num + added_curves_num; @@ -280,6 +293,10 @@ void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inp curves.resize(new_points_num, new_curves_num); MutableSpan positions_cu = curves.positions_for_write(); + /* Initialize attachment information. */ + MutableSpan surface_uv_coords = curves.surface_uv_coords_for_write(); + surface_uv_coords.take_back(added_curves_num).copy_from(used_uvs); + /* Determine length of new curves. */ Array new_lengths_cu(added_curves_num); if (inputs.interpolate_length) { @@ -306,25 +323,11 @@ void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inp Array new_normals_su(added_curves_num); threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) { for (const int i : range) { - const int looptri_index = inputs.looptri_indices[i]; - const float3 &bary_coord = inputs.bary_coords[i]; new_normals_su[i] = compute_surface_point_normal( - inputs.surface_looptris[looptri_index], bary_coord, inputs.corner_normals_su); + *looptris[i], bary_coords[i], inputs.corner_normals_su); } }); - /* Propagate attachment information. */ - if (!inputs.surface_uv_map.is_empty()) { - MutableSpan surface_uv_coords = curves.surface_uv_coords_for_write(); - bke::mesh_surface_sample::sample_corner_attribute( - *inputs.surface, - inputs.looptri_indices, - inputs.bary_coords, - GVArray::ForSpan(inputs.surface_uv_map), - IndexRange(added_curves_num), - surface_uv_coords.take_back(added_curves_num)); - } - /* Update selection arrays when available. */ const VArray points_selection = curves.selection_point_float(); if (points_selection.is_span()) { @@ -340,25 +343,22 @@ void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inp /* Initialize position attribute. */ if (inputs.interpolate_shape) { interpolate_position_with_interpolation(curves, - inputs.root_positions_cu, + root_positions_cu, neighbors_per_curve, old_curves_num, new_lengths_cu, new_normals_su, - inputs.surface_to_curves_normal_mat, - inputs.curves_to_surface_mat, - *inputs.surface_bvh, - inputs.surface_looptris, - *inputs.surface, + *inputs.transforms, + *inputs.reverse_uv_sampler, inputs.corner_normals_su); } else { interpolate_position_without_interpolation(curves, old_curves_num, - inputs.root_positions_cu, + root_positions_cu, new_lengths_cu, new_normals_su, - inputs.surface_to_curves_normal_mat); + inputs.transforms->surface_to_curves_normal); } /* Set curve types. */ diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 0544f304283..4b3b184536b 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -204,7 +204,8 @@ struct GatherTasks { /* Volumes only have very simple support currently. Only the first found volume is put into the * output. */ - UserCounter first_volume; + UserCounter first_volume; + UserCounter first_edit_data; }; /** Current offsets while during the gather operation. */ @@ -582,7 +583,16 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, const VolumeComponent *volume_component = static_cast(component); if (!gather_info.r_tasks.first_volume) { volume_component->user_add(); - gather_info.r_tasks.first_volume = const_cast(volume_component); + gather_info.r_tasks.first_volume = volume_component; + } + break; + } + case GEO_COMPONENT_TYPE_EDIT: { + const GeometryComponentEditData *edit_component = + static_cast(component); + if (!gather_info.r_tasks.first_edit_data) { + edit_component->user_add(); + gather_info.r_tasks.first_edit_data = edit_component; } break; } @@ -1405,6 +1415,9 @@ GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOp if (gather_info.r_tasks.first_volume) { new_geometry_set.add(*gather_info.r_tasks.first_volume); } + if (gather_info.r_tasks.first_edit_data) { + new_geometry_set.add(*gather_info.r_tasks.first_edit_data); + } return new_geometry_set; } -- cgit v1.2.3