This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/mesh_sample.cc
Campbell Barton c434782e3a File headers: SPDX License migration
Use a shorter/simpler license convention, stops the header taking so
much space.

Follow the SPDX license specification: https://spdx.org/licenses

- C/C++/objc/objc++
- Python
- Shell Scripts
- CMake, GNUmakefile

While most of the source tree has been included

- `./extern/` was left out.
- `./intern/cycles` & `./intern/atomic` are also excluded because they
  use different header conventions.

doc/license/SPDX-license-identifiers.txt has been added to list SPDX all
used identifiers.

See P2788 for the script that automated these edits.

Reviewed By: brecht, mont29, sergey

Ref D14069
2022-02-11 09:14:36 +11:00

263 lines
9.4 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
namespace blender::bke::mesh_surface_sample {
template<typename T>
BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const VArray<T> &data_in,
const IndexMask mask,
const MutableSpan<T> data_out)
{
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
BKE_mesh_runtime_looptri_len(&mesh)};
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 = mesh.mloop[looptri.tri[0]].v;
const int v1_index = mesh.mloop[looptri.tri[1]].v;
const int v2_index = mesh.mloop[looptri.tri[2]].v;
const T v0 = data_in[v0_index];
const T v1 = data_in[v1_index];
const T v2 = data_in[v2_index];
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
data_out[i] = interpolated_value;
}
}
void sample_point_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const GVArray &data_in,
const IndexMask mask,
const GMutableSpan data_out)
{
BLI_assert(data_in.size() == mesh.totvert);
BLI_assert(data_in.type() == data_out.type());
const CPPType &type = data_in.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_point_attribute<T>(
mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>());
});
}
template<typename T>
BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const VArray<T> &data_in,
const IndexMask mask,
const MutableSpan<T> data_out)
{
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
BKE_mesh_runtime_looptri_len(&mesh)};
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 = data_in[loop_index_0];
const T v1 = data_in[loop_index_1];
const T v2 = data_in[loop_index_2];
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
data_out[i] = interpolated_value;
}
}
void sample_corner_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const GVArray &data_in,
const IndexMask mask,
const GMutableSpan data_out)
{
BLI_assert(data_in.size() == mesh.totloop);
BLI_assert(data_in.type() == data_out.type());
const CPPType &type = data_in.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_corner_attribute<T>(
mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>());
});
}
template<typename T>
void sample_face_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const VArray<T> &data_in,
const IndexMask mask,
const MutableSpan<T> data_out)
{
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
BKE_mesh_runtime_looptri_len(&mesh)};
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const int poly_index = looptri.poly;
data_out[i] = data_in[poly_index];
}
}
void sample_face_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const GVArray &data_in,
const IndexMask mask,
const GMutableSpan data_out)
{
BLI_assert(data_in.size() == mesh.totpoly);
BLI_assert(data_in.type() == data_out.type());
const CPPType &type = data_in.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), mask, data_out.typed<T>());
});
}
MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh,
const IndexMask mask,
const Span<float3> positions,
const Span<int> looptri_indices)
: mesh_(mesh), mask_(mask), positions_(positions), looptri_indices_(looptri_indices)
{
BLI_assert(positions.size() == looptri_indices.size());
}
Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
{
if (!bary_coords_.is_empty()) {
BLI_assert(bary_coords_.size() >= mask_.min_array_size());
return bary_coords_;
}
bary_coords_.reinitialize(mask_.min_array_size());
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_),
BKE_mesh_runtime_looptri_len(mesh_)};
for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
const int v0_index = mesh_->mloop[looptri.tri[0]].v;
const int v1_index = mesh_->mloop[looptri.tri[1]].v;
const int v2_index = mesh_->mloop[looptri.tri[2]].v;
interp_weights_tri_v3(bary_coords_[i],
mesh_->mvert[v0_index].co,
mesh_->mvert[v1_index].co,
mesh_->mvert[v2_index].co,
positions_[i]);
}
return bary_coords_;
}
Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
{
if (!nearest_weights_.is_empty()) {
BLI_assert(nearest_weights_.size() >= mask_.min_array_size());
return nearest_weights_;
}
nearest_weights_.reinitialize(mask_.min_array_size());
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_),
BKE_mesh_runtime_looptri_len(mesh_)};
for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
const int v0_index = mesh_->mloop[looptri.tri[0]].v;
const int v1_index = mesh_->mloop[looptri.tri[1]].v;
const int v2_index = mesh_->mloop[looptri.tri[2]].v;
const float d0 = len_squared_v3v3(positions_[i], mesh_->mvert[v0_index].co);
const float d1 = len_squared_v3v3(positions_[i], mesh_->mvert[v1_index].co);
const float d2 = len_squared_v3v3(positions_[i], mesh_->mvert[v2_index].co);
nearest_weights_[i] = MIN3_PAIR(d0, d1, d2, float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
}
return nearest_weights_;
}
void MeshAttributeInterpolator::sample_data(const GVArray &src,
const AttributeDomain domain,
const eAttributeMapMode mode,
const GMutableSpan dst)
{
if (src.is_empty() || dst.is_empty()) {
return;
}
/* Compute barycentric coordinates only when they are needed. */
Span<float3> weights;
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
switch (mode) {
case eAttributeMapMode::INTERPOLATED:
weights = ensure_barycentric_coords();
break;
case eAttributeMapMode::NEAREST:
weights = ensure_nearest_weights();
break;
}
}
/* Interpolate the source attributes on the surface. */
switch (domain) {
case ATTR_DOMAIN_POINT: {
sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst);
break;
}
case ATTR_DOMAIN_FACE: {
sample_face_attribute(*mesh_, looptri_indices_, src, mask_, dst);
break;
}
case ATTR_DOMAIN_CORNER: {
sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst);
break;
}
case ATTR_DOMAIN_EDGE: {
/* Not yet supported. */
break;
}
default: {
BLI_assert_unreachable();
break;
}
}
}
void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute,
OutputAttribute &dst_attribute,
eAttributeMapMode mode)
{
if (src_attribute && dst_attribute) {
this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span());
}
}
} // namespace blender::bke::mesh_surface_sample