Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/geometry/intern/add_curves_on_mesh.cc')
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc182
1 files changed, 102 insertions, 80 deletions
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
index 34551bd474f..7184d774a22 100644
--- a/source/blender/geometry/intern/add_curves_on_mesh.cc
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -1,9 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_length_parameterize.hh"
+
+#include "BKE_attribute_math.hh"
#include "BKE_mesh_sample.hh"
-#include "BKE_spline.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:
@@ -25,9 +28,9 @@ struct NeighborCurve {
static constexpr int max_neighbors = 5;
using NeighborCurves = Vector<NeighborCurve, max_neighbors>;
-static float3 compute_surface_point_normal(const MLoopTri &looptri,
- const float3 &bary_coord,
- const Span<float3> corner_normals)
+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];
@@ -134,27 +137,26 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves,
const int old_curves_num,
const Span<float> new_lengths_cu,
const Span<float3> new_normals_su,
- const float4x4 &surface_to_curves_normal_mat,
- const float4x4 &curves_to_surface_mat,
- const BVHTreeFromMesh &surface_bvh,
- const Span<MLoopTri> surface_looptris,
- const Mesh &surface,
+ const bke::CurvesSurfaceTransforms &transforms,
+ const ReverseUVSampler &reverse_uv_sampler,
const Span<float3> corner_normals_su)
{
MutableSpan<float3> positions_cu = curves.positions_for_write();
const int added_curves_num = root_positions_cu.size();
+ const Span<float2> uv_coords = curves.surface_uv_coords();
+
threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const NeighborCurves &neighbors = neighbors_per_curve[i];
- const int curve_i = old_curves_num + i;
+ for (const int added_curve_i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[added_curve_i];
+ const int curve_i = old_curves_num + added_curve_i;
const IndexRange points = curves.points_for_curve(curve_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 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(transforms.surface_to_curves_normal * normal_su);
- const float3 &root_cu = root_positions_cu[i];
+ const float3 &root_cu = root_positions_cu[added_curve_i];
if (neighbors.is_empty()) {
/* If there are no neighbors, just make a straight line. */
@@ -167,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<BVHTreeFromMesh *>(&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
@@ -197,48 +188,87 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves,
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();
+ /* Sample the positions on neighbors and mix them into the final positions of the curve.
+ * 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.
+ *
+ * TODO: The lengths can be cached so they aren't recomputed if a curve is a neighbor for
+ * multiple new curves. Also, allocations could be avoided by reusing some arrays. */
+
+ const Span<float3> neighbor_positions_cu = positions_cu.slice(neighbor_points);
+ if (neighbor_positions_cu.size() == 1) {
+ /* Skip interpolating positions from neighbors with only one point. */
+ continue;
+ }
+ Array<float, 32> lengths(length_parameterize::segments_num(neighbor_points.size(), false));
+ length_parameterize::accumulate_lengths<float3>(neighbor_positions_cu, false, lengths);
+ const float neighbor_length_cu = lengths.last();
- const float neighbor_length_cu = neighbor_spline.length();
+ Array<float, 32> sample_lengths(points.size());
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;
+ for (const int i : sample_lengths.index_range()) {
+ sample_lengths[i] = i * resample_factor * neighbor_length_cu;
+ }
+
+ Array<int, 32> indices(points.size());
+ Array<float, 32> factors(points.size());
+ length_parameterize::sample_at_lengths(lengths, sample_lengths, indices, factors);
+
+ for (const int i : IndexRange(points.size())) {
+ const float3 sample_cu = math::interpolate(neighbor_positions_cu[indices[i]],
+ neighbor_positions_cu[indices[i] + 1],
+ factors[i]);
+ const float3 relative_to_root_cu = sample_cu - neighbor_root_cu;
+ float3 rotated_relative_coord = relative_to_root_cu;
mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
- positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
+ positions_cu[points[i]] += neighbor.weight * rotated_relative_coord;
}
}
}
});
}
-void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs)
+AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
+ const AddCurvesOnMeshInputs &inputs)
{
+ AddCurvesOnMeshOutputs outputs;
+
const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count ||
inputs.interpolate_shape;
+ Vector<float3> root_positions_cu;
+ Vector<float3> bary_coords;
+ Vector<const MLoopTri *> looptris;
+ Vector<float2> 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) {
+ outputs.uv_error = true;
+ continue;
+ }
+ const MLoopTri &looptri = *result.looptri;
+ bary_coords.append(result.bary_weights);
+ looptris.append(&looptri);
+ const float3 root_position_su = attribute_math::mix3<float3>(
+ 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<NeighborCurves> 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;
@@ -267,6 +297,10 @@ void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inp
curves.resize(new_points_num, new_curves_num);
MutableSpan<float3> positions_cu = curves.positions_for_write();
+ /* Initialize attachment information. */
+ MutableSpan<float2> 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<float> new_lengths_cu(added_curves_num);
if (inputs.interpolate_length) {
@@ -293,25 +327,11 @@ void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inp
Array<float3> 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<float2> 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<float> points_selection = curves.selection_point_float();
if (points_selection.is_span()) {
@@ -327,28 +347,30 @@ 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. */
+ MutableSpan<int8_t> types_span = curves.curve_types_for_write();
+ types_span.drop_front(old_curves_num).fill(CURVE_TYPE_CATMULL_ROM);
curves.update_curve_types();
+
+ return outputs;
}
} // namespace blender::geometry