Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_sample.cc
| Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
| void sample_point_attribute(const Mesh &mesh, | void sample_point_attribute(const Mesh &mesh, | ||||
| const Span<int> looptri_indices, | const Span<int> looptri_indices, | ||||
| const Span<float3> bary_coords, | const Span<float3> bary_coords, | ||||
| const GVArray &data_in, | const GVArray &data_in, | ||||
| const IndexMask mask, | const IndexMask mask, | ||||
| const GMutableSpan data_out) | const GMutableSpan data_out) | ||||
| { | { | ||||
| BLI_assert(data_out.size() == looptri_indices.size()); | |||||
| BLI_assert(data_out.size() == bary_coords.size()); | |||||
| BLI_assert(data_in.size() == mesh.totvert); | BLI_assert(data_in.size() == mesh.totvert); | ||||
| BLI_assert(data_in.type() == data_out.type()); | BLI_assert(data_in.type() == data_out.type()); | ||||
| const CPPType &type = data_in.type(); | const CPPType &type = data_in.type(); | ||||
| attribute_math::convert_to_static_type(type, [&](auto dummy) { | attribute_math::convert_to_static_type(type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| sample_point_attribute<T>( | sample_point_attribute<T>( | ||||
| mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>()); | mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>()); | ||||
| Show All 31 Lines | |||||
| void sample_corner_attribute(const Mesh &mesh, | void sample_corner_attribute(const Mesh &mesh, | ||||
| const Span<int> looptri_indices, | const Span<int> looptri_indices, | ||||
| const Span<float3> bary_coords, | const Span<float3> bary_coords, | ||||
| const GVArray &data_in, | const GVArray &data_in, | ||||
| const IndexMask mask, | const IndexMask mask, | ||||
| const GMutableSpan data_out) | const GMutableSpan data_out) | ||||
| { | { | ||||
| BLI_assert(data_out.size() == looptri_indices.size()); | |||||
| BLI_assert(data_out.size() == bary_coords.size()); | |||||
| BLI_assert(data_in.size() == mesh.totloop); | BLI_assert(data_in.size() == mesh.totloop); | ||||
| BLI_assert(data_in.type() == data_out.type()); | BLI_assert(data_in.type() == data_out.type()); | ||||
| const CPPType &type = data_in.type(); | const CPPType &type = data_in.type(); | ||||
| attribute_math::convert_to_static_type(type, [&](auto dummy) { | attribute_math::convert_to_static_type(type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| sample_corner_attribute<T>( | sample_corner_attribute<T>( | ||||
| mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>()); | mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>()); | ||||
| Show All 19 Lines | |||||
| } | } | ||||
| void sample_face_attribute(const Mesh &mesh, | void sample_face_attribute(const Mesh &mesh, | ||||
| const Span<int> looptri_indices, | const Span<int> looptri_indices, | ||||
| const GVArray &data_in, | const GVArray &data_in, | ||||
| const IndexMask mask, | const IndexMask mask, | ||||
| const GMutableSpan data_out) | const GMutableSpan data_out) | ||||
| { | { | ||||
| BLI_assert(data_out.size() == looptri_indices.size()); | |||||
| BLI_assert(data_in.size() == mesh.totpoly); | BLI_assert(data_in.size() == mesh.totpoly); | ||||
| BLI_assert(data_in.type() == data_out.type()); | BLI_assert(data_in.type() == data_out.type()); | ||||
| const CPPType &type = data_in.type(); | const CPPType &type = data_in.type(); | ||||
| attribute_math::convert_to_static_type(type, [&](auto dummy) { | attribute_math::convert_to_static_type(type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), mask, data_out.typed<T>()); | sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), mask, data_out.typed<T>()); | ||||
| }); | }); | ||||
| } | } | ||||
| MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh, | MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh, | ||||
| const IndexMask mask, | |||||
| const Span<float3> positions, | const Span<float3> positions, | ||||
| const Span<int> looptri_indices) | const Span<int> looptri_indices) | ||||
| : mesh_(mesh), positions_(positions), looptri_indices_(looptri_indices) | : mesh_(mesh), mask_(mask), positions_(positions), looptri_indices_(looptri_indices) | ||||
| { | { | ||||
| BLI_assert(positions.size() == looptri_indices.size()); | BLI_assert(positions.size() == looptri_indices.size()); | ||||
| } | } | ||||
| Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords() | Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords() | ||||
| { | { | ||||
| if (!bary_coords_.is_empty()) { | if (!bary_coords_.is_empty()) { | ||||
| BLI_assert(bary_coords_.size() == positions_.size()); | BLI_assert(nearest_weights_.size() >= mask_.min_array_size()); | ||||
| return bary_coords_; | return bary_coords_; | ||||
| } | } | ||||
| bary_coords_.reinitialize(positions_.size()); | bary_coords_.reinitialize(mask_.min_array_size()); | ||||
| const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_), | const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_), | ||||
| BKE_mesh_runtime_looptri_len(mesh_)}; | BKE_mesh_runtime_looptri_len(mesh_)}; | ||||
| for (const int i : bary_coords_.index_range()) { | for (const int i : mask_) { | ||||
| const int looptri_index = looptri_indices_[i]; | const int looptri_index = looptri_indices_[i]; | ||||
| const MLoopTri &looptri = looptris[looptri_index]; | const MLoopTri &looptri = looptris[looptri_index]; | ||||
| const int v0_index = mesh_->mloop[looptri.tri[0]].v; | const int v0_index = mesh_->mloop[looptri.tri[0]].v; | ||||
| const int v1_index = mesh_->mloop[looptri.tri[1]].v; | const int v1_index = mesh_->mloop[looptri.tri[1]].v; | ||||
| const int v2_index = mesh_->mloop[looptri.tri[2]].v; | const int v2_index = mesh_->mloop[looptri.tri[2]].v; | ||||
| interp_weights_tri_v3(bary_coords_[i], | interp_weights_tri_v3(bary_coords_[i], | ||||
| mesh_->mvert[v0_index].co, | mesh_->mvert[v0_index].co, | ||||
| mesh_->mvert[v1_index].co, | mesh_->mvert[v1_index].co, | ||||
| mesh_->mvert[v2_index].co, | mesh_->mvert[v2_index].co, | ||||
| positions_[i]); | positions_[i]); | ||||
| } | } | ||||
| return bary_coords_; | return bary_coords_; | ||||
| } | } | ||||
| Span<float3> MeshAttributeInterpolator::ensure_nearest_weights() | Span<float3> MeshAttributeInterpolator::ensure_nearest_weights() | ||||
| { | { | ||||
| if (!nearest_weights_.is_empty()) { | if (!nearest_weights_.is_empty()) { | ||||
| BLI_assert(nearest_weights_.size() == positions_.size()); | BLI_assert(nearest_weights_.size() >= mask_.min_array_size()); | ||||
| return nearest_weights_; | return nearest_weights_; | ||||
| } | } | ||||
| nearest_weights_.reinitialize(positions_.size()); | nearest_weights_.reinitialize(mask_.min_array_size()); | ||||
| const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_), | const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_), | ||||
| BKE_mesh_runtime_looptri_len(mesh_)}; | BKE_mesh_runtime_looptri_len(mesh_)}; | ||||
| for (const int i : nearest_weights_.index_range()) { | for (const int i : mask_) { | ||||
| const int looptri_index = looptri_indices_[i]; | const int looptri_index = looptri_indices_[i]; | ||||
| const MLoopTri &looptri = looptris[looptri_index]; | const MLoopTri &looptri = looptris[looptri_index]; | ||||
| const int v0_index = mesh_->mloop[looptri.tri[0]].v; | const int v0_index = mesh_->mloop[looptri.tri[0]].v; | ||||
| const int v1_index = mesh_->mloop[looptri.tri[1]].v; | const int v1_index = mesh_->mloop[looptri.tri[1]].v; | ||||
| const int v2_index = mesh_->mloop[looptri.tri[2]].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 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 d1 = len_squared_v3v3(positions_[i], mesh_->mvert[v1_index].co); | ||||
| const float d2 = len_squared_v3v3(positions_[i], mesh_->mvert[v2_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)); | nearest_weights_[i] = MIN3_PAIR(d0, d1, d2, float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1)); | ||||
| } | } | ||||
| return nearest_weights_; | return nearest_weights_; | ||||
| } | } | ||||
| void MeshAttributeInterpolator::sample_data(const GVArray &src, | void MeshAttributeInterpolator::sample_data(const GVArray &src, | ||||
| const AttributeDomain domain, | const AttributeDomain domain, | ||||
| const eAttributeMapMode mode, | const eAttributeMapMode mode, | ||||
| const IndexMask mask, | |||||
| const GMutableSpan dst) | const GMutableSpan dst) | ||||
| { | { | ||||
| if (src.is_empty() || dst.is_empty()) { | if (src.is_empty() || dst.is_empty()) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Compute barycentric coordinates only when they are needed. */ | /* Compute barycentric coordinates only when they are needed. */ | ||||
| Span<float3> weights; | Span<float3> weights; | ||||
| if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { | if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { | ||||
| switch (mode) { | switch (mode) { | ||||
| case eAttributeMapMode::INTERPOLATED: | case eAttributeMapMode::INTERPOLATED: | ||||
| weights = ensure_barycentric_coords(); | weights = ensure_barycentric_coords(); | ||||
| break; | break; | ||||
| case eAttributeMapMode::NEAREST: | case eAttributeMapMode::NEAREST: | ||||
| weights = ensure_nearest_weights(); | weights = ensure_nearest_weights(); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* Interpolate the source attributes on the surface. */ | /* Interpolate the source attributes on the surface. */ | ||||
| switch (domain) { | switch (domain) { | ||||
| case ATTR_DOMAIN_POINT: { | case ATTR_DOMAIN_POINT: { | ||||
| sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask, dst); | sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst); | ||||
| break; | break; | ||||
| } | } | ||||
| case ATTR_DOMAIN_FACE: { | case ATTR_DOMAIN_FACE: { | ||||
| sample_face_attribute(*mesh_, looptri_indices_, src, mask, dst); | sample_face_attribute(*mesh_, looptri_indices_, src, mask_, dst); | ||||
| break; | break; | ||||
| } | } | ||||
| case ATTR_DOMAIN_CORNER: { | case ATTR_DOMAIN_CORNER: { | ||||
| sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask, dst); | sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst); | ||||
| break; | break; | ||||
| } | } | ||||
| case ATTR_DOMAIN_EDGE: { | case ATTR_DOMAIN_EDGE: { | ||||
| /* Not yet supported. */ | /* Not yet supported. */ | ||||
| break; | break; | ||||
| } | } | ||||
| default: { | default: { | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute, | void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute, | ||||
| OutputAttribute &dst_attribute, | OutputAttribute &dst_attribute, | ||||
| eAttributeMapMode mode) | eAttributeMapMode mode) | ||||
| { | { | ||||
| if (src_attribute && dst_attribute) { | if (src_attribute && dst_attribute) { | ||||
| this->sample_data(*src_attribute.varray, | this->sample_data(*src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); | ||||
| src_attribute.domain, | |||||
| mode, | |||||
| IndexMask(dst_attribute->size()), | |||||
| dst_attribute.as_span()); | |||||
| } | } | ||||
| } | } | ||||
| } // namespace blender::bke::mesh_surface_sample | } // namespace blender::bke::mesh_surface_sample | ||||