Cleanup: Simplify and deduplicate mesh sampling code

It arguably reads easier if simple operations like reading from indices
of an array don't each get their own line. Also the same corner
attribute sampling was repeated in a few places. And add a new
function to sample normals from the corner domain, and use
lower level arguments to the lower level functions (i.e. not just
a mesh pointer, but the necessary data arrays).
This commit is contained in:
Hans Goudey
2023-04-28 14:44:08 -04:00
parent f8cc6cc866
commit bec033e057
5 changed files with 90 additions and 104 deletions

View File

@@ -23,21 +23,29 @@ class RandomNumberGenerator;
namespace blender::bke::mesh_surface_sample {
void sample_point_attribute(const Mesh &mesh,
void sample_point_attribute(Span<int> corner_verts,
Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<float3> bary_coords,
const GVArray &src,
IndexMask mask,
GMutableSpan dst);
void sample_corner_attribute(const Mesh &mesh,
void sample_corner_attribute(Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<float3> bary_coords,
const GVArray &src,
IndexMask mask,
GMutableSpan dst);
void sample_face_attribute(const Mesh &mesh,
void sample_corner_normals(Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<float3> bary_coords,
Span<float3> src,
IndexMask mask,
MutableSpan<float3> dst);
void sample_face_attribute(Span<MLoopTri> looptris,
Span<int> looptri_indices,
const GVArray &src,
IndexMask mask,
@@ -143,4 +151,15 @@ inline T sample_corner_attrribute_with_bary_coords(const float3 &bary_weights,
corner_attribute[looptri.tri[2]]);
}
template<typename T>
inline T sample_corner_attrribute_with_bary_coords(const float3 &bary_weights,
const MLoopTri &looptri,
const VArray<T> &corner_attribute)
{
return attribute_math::mix3(bary_weights,
corner_attribute[looptri.tri[0]],
corner_attribute[looptri.tri[1]],
corner_attribute[looptri.tri[2]]);
}
} // namespace blender::bke::mesh_surface_sample

View File

@@ -10,111 +10,103 @@
#include "DNA_meshdata_types.h"
#include "BLI_rand.hh"
#include "BLI_task.hh"
namespace blender::bke::mesh_surface_sample {
template<typename T>
BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
BLI_NOINLINE static void sample_point_attribute(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const VArray<T> &src,
const IndexMask mask,
const MutableSpan<T> dst)
{
const Span<int> corner_verts = mesh.corner_verts();
const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
const int v0_index = corner_verts[looptri.tri[0]];
const int v1_index = corner_verts[looptri.tri[1]];
const int v2_index = corner_verts[looptri.tri[2]];
const T v0 = src[v0_index];
const T v1 = src[v1_index];
const T v2 = src[v2_index];
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
dst[i] = interpolated_value;
const MLoopTri &tri = looptris[looptri_indices[i]];
dst[i] = attribute_math::mix3(bary_coords[i],
src[corner_verts[tri.tri[0]]],
src[corner_verts[tri.tri[1]]],
src[corner_verts[tri.tri[2]]]);
}
}
void sample_point_attribute(const Mesh &mesh,
void sample_point_attribute(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const GVArray &src,
const IndexMask mask,
const GMutableSpan dst)
{
BLI_assert(src.size() == mesh.totvert);
BLI_assert(src.type() == dst.type());
const CPPType &type = src.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_point_attribute<T>(
mesh, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>());
sample_point_attribute<T>(corner_verts,
looptris,
looptri_indices,
bary_coords,
src.typed<T>(),
mask,
dst.typed<T>());
});
}
template<typename T>
BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
BLI_NOINLINE static void sample_corner_attribute(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const VArray<T> &src,
const IndexMask mask,
const MutableSpan<T> dst)
{
const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
const int loop_index_0 = looptri.tri[0];
const int loop_index_1 = looptri.tri[1];
const int loop_index_2 = looptri.tri[2];
const T v0 = src[loop_index_0];
const T v1 = src[loop_index_1];
const T v2 = src[loop_index_2];
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
dst[i] = interpolated_value;
const MLoopTri &tri = looptris[looptri_indices[i]];
dst[i] = sample_corner_attrribute_with_bary_coords(bary_coords[i], tri, src);
}
}
void sample_corner_attribute(const Mesh &mesh,
void sample_corner_normals(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const Span<float3> src,
const IndexMask mask,
const MutableSpan<float3> dst)
{
for (const int i : mask) {
const MLoopTri &tri = looptris[looptri_indices[i]];
const float3 value = sample_corner_attrribute_with_bary_coords(bary_coords[i], tri, src);
dst[i] = math::normalize(value);
}
}
void sample_corner_attribute(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const GVArray &src,
const IndexMask mask,
const GMutableSpan dst)
{
BLI_assert(src.size() == mesh.totloop);
BLI_assert(src.type() == dst.type());
const CPPType &type = src.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_corner_attribute<T>(
mesh, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>());
looptris, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>());
});
}
template<typename T>
void sample_face_attribute(const Mesh &mesh,
void sample_face_attribute(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const VArray<T> &src,
const IndexMask mask,
const MutableSpan<T> dst)
{
const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
@@ -123,19 +115,18 @@ void sample_face_attribute(const Mesh &mesh,
}
}
void sample_face_attribute(const Mesh &mesh,
void sample_face_attribute(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const GVArray &src,
const IndexMask mask,
const GMutableSpan dst)
{
BLI_assert(src.size() == mesh.totpoly);
BLI_assert(src.type() == dst.type());
const CPPType &type = src.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_face_attribute<T>(mesh, looptri_indices, src.typed<T>(), mask, dst.typed<T>());
sample_face_attribute<T>(looptris, looptri_indices, src.typed<T>(), mask, dst.typed<T>());
});
}
@@ -161,14 +152,8 @@ Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
const Span<MLoopTri> looptris = mesh_->looptris();
for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
interp_weights_tri_v3(bary_coords_[i],
positions[corner_verts[looptri.tri[0]]],
positions[corner_verts[looptri.tri[1]]],
positions[corner_verts[looptri.tri[2]]],
positions_[i]);
const MLoopTri &tri = looptris[looptri_indices_[i]];
bary_coords_[i] = compute_bary_coord_in_triangle(positions, corner_verts, tri, positions_[i]);
}
return bary_coords_;
}
@@ -223,13 +208,14 @@ void MeshAttributeInterpolator::sample_data(const GVArray &src,
/* Interpolate the source attributes on the surface. */
switch (domain) {
case ATTR_DOMAIN_POINT:
sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst);
sample_point_attribute(
mesh_->corner_verts(), mesh_->looptris(), looptri_indices_, weights, src, mask_, dst);
break;
case ATTR_DOMAIN_FACE:
sample_face_attribute(*mesh_, looptri_indices_, src, mask_, dst);
sample_face_attribute(mesh_->looptris(), looptri_indices_, src, mask_, dst);
break;
case ATTR_DOMAIN_CORNER:
sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst);
sample_corner_attribute(mesh_->looptris(), looptri_indices_, weights, src, mask_, dst);
break;
case ATTR_DOMAIN_EDGE:
/* Not yet supported. */

View File

@@ -33,6 +33,7 @@
#include "BKE_mesh.hh"
#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -632,19 +633,11 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
}
if (!surface_uv_map.is_empty()) {
const MLoopTri &looptri = surface_looptris[looptri_index];
const int corner0 = looptri.tri[0];
const int corner1 = looptri.tri[1];
const int corner2 = looptri.tri[2];
const float2 &uv0 = surface_uv_map[corner0];
const float2 &uv1 = surface_uv_map[corner1];
const float2 &uv2 = surface_uv_map[corner2];
const float3 &p0_su = surface_positions[corner_verts[corner0]];
const float3 &p1_su = surface_positions[corner_verts[corner1]];
const float3 &p2_su = surface_positions[corner_verts[corner2]];
float3 bary_coords;
interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
const MLoopTri &tri = surface_looptris[looptri_index];
const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
surface_positions, corner_verts, tri, new_first_point_pos_su);
const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
bary_coords, tri, surface_uv_map);
surface_uv_coords[curve_i] = uv;
}
}

View File

@@ -340,7 +340,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
/* Find surface normal at root points. */
Array<float3> new_normals_su(added_curves_num);
bke::mesh_surface_sample::sample_corner_attribute(
*inputs.surface,
inputs.surface_looptris,
looptri_indices,
bary_coords,
VArray<float3>::ForSpan(inputs.corner_normals_su),

View File

@@ -255,7 +255,8 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
{
switch (source_domain) {
case ATTR_DOMAIN_POINT: {
bke::mesh_surface_sample::sample_point_attribute(mesh,
bke::mesh_surface_sample::sample_point_attribute(mesh.corner_verts(),
mesh.looptris(),
looptri_indices,
bary_coords,
source_data,
@@ -264,7 +265,7 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
break;
}
case ATTR_DOMAIN_CORNER: {
bke::mesh_surface_sample::sample_corner_attribute(mesh,
bke::mesh_surface_sample::sample_corner_attribute(mesh.looptris(),
looptri_indices,
bary_coords,
source_data,
@@ -273,8 +274,11 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
break;
}
case ATTR_DOMAIN_FACE: {
bke::mesh_surface_sample::sample_face_attribute(
mesh, looptri_indices, source_data, IndexMask(output_data.size()), output_data);
bke::mesh_surface_sample::sample_face_attribute(mesh.looptris(),
looptri_indices,
source_data,
IndexMask(output_data.size()),
output_data);
break;
}
default: {
@@ -298,25 +302,19 @@ BLI_NOINLINE static void propagate_existing_attributes(
const AttributeIDRef attribute_id = entry.key;
const eCustomDataType output_data_type = entry.value.data_type;
GAttributeReader source_attribute = mesh_attributes.lookup(attribute_id);
if (!source_attribute) {
GAttributeReader src = mesh_attributes.lookup(attribute_id);
if (!src) {
continue;
}
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
GSpanAttributeWriter attribute_out = point_attributes.lookup_or_add_for_write_only_span(
GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
if (!dst) {
continue;
}
interpolate_attribute(mesh,
bary_coords,
looptri_indices,
source_attribute.domain,
source_attribute.varray,
attribute_out.span);
attribute_out.finish();
interpolate_attribute(mesh, bary_coords, looptri_indices, src.domain, src.varray, dst.span);
dst.finish();
}
}
@@ -337,19 +335,9 @@ static void compute_normal_outputs(const Mesh &mesh,
const_cast<Mesh *>(&mesh), nullptr, reinterpret_cast<float(*)[3]>(corner_normals.data()));
const Span<MLoopTri> looptris = mesh.looptris();
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) {
for (const int i : range) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
const float3 normal = math::normalize(
bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
bary_coord, looptri, corner_normals.as_span()));
r_normals[i] = normal;
}
bke::mesh_surface_sample::sample_corner_normals(
looptris, looptri_indices, bary_coords, corner_normals, range, r_normals);
});
}