diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2021-06-17 11:31:53 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2021-06-17 23:11:32 +0300 |
commit | 4b673ebb990684af4a429d963a1026ddf3f2552f (patch) | |
tree | e5914b52a95fb60ed3ba3fcc63ceb71c3e2499ad /source/blender/blenkernel/intern/mesh_sample.cc | |
parent | 577d6d3f872206c99dc95c8afaff47ca0339d7fc (diff) |
Raycast geometry node.
The //Raycast// node intersects rays from one geometry onto another.
It computes hit points on the target mesh and returns normals, distances
and any surface attribute specified by the user.
A ray starts on each point of the input //Geometry//. Rays continue
in the //Ray Direction// until they either hit the //Target Geometry//
or reach the //Ray Length// limit. If the target is hit, the value of the
//Is Hit// attribute in the output mesh will be true. //Hit Position//,
//Hit Normal//, //Hit Distance// and //Hit Index// are the properties of the
target mesh at the intersection point. In addition, a //Target Attribute//
can be specified that is interpolated at the hit point and the result
stored in //Hit Attribute//.
Docs: D11620
Reviewed By: HooglyBoogly
Differential Revision: https://developer.blender.org/D11619
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_sample.cc')
-rw-r--r-- | source/blender/blenkernel/intern/mesh_sample.cc | 119 |
1 files changed, 118 insertions, 1 deletions
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index 91c9951ae89..7bc73762506 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -14,6 +14,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" @@ -23,7 +24,7 @@ namespace blender::bke::mesh_surface_sample { -static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh) +Span<MLoopTri> get_mesh_looptris(const Mesh &mesh) { /* This only updates a cache and can be considered to be logically const. */ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh)); @@ -155,4 +156,120 @@ void sample_face_attribute(const Mesh &mesh, }); } +MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh, + const Span<float3> positions, + const Span<int> looptri_indices) + : mesh_(mesh), 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() == positions_.size()); + return bary_coords_; + } + bary_coords_.reinitialize(positions_.size()); + + Span<MLoopTri> looptris = get_mesh_looptris(*mesh_); + + for (const int i : bary_coords_.index_range()) { + 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() == positions_.size()); + return nearest_weights_; + } + nearest_weights_.reinitialize(positions_.size()); + + Span<MLoopTri> looptris = get_mesh_looptris(*mesh_); + + for (const int i : nearest_weights_.index_range()) { + 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_attribute(const ReadAttributeLookup &src_attribute, + OutputAttribute &dst_attribute, + eAttributeMapMode mode) +{ + if (!src_attribute || !dst_attribute) { + return; + } + const GVArray &src_varray = *src_attribute.varray; + GMutableSpan dst_span = dst_attribute.as_span(); + if (src_varray.is_empty() || dst_span.is_empty()) { + return; + } + + /* Compute barycentric coordinates only when they are needed. */ + Span<float3> weights; + if (ELEM(src_attribute.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 (src_attribute.domain) { + case ATTR_DOMAIN_POINT: { + sample_point_attribute( + *mesh_, looptri_indices_, weights, src_varray, dst_span); + break; + } + case ATTR_DOMAIN_FACE: { + sample_face_attribute( + *mesh_, looptri_indices_, src_varray, dst_span); + break; + } + case ATTR_DOMAIN_CORNER: { + sample_corner_attribute( + *mesh_, looptri_indices_, weights, src_varray, dst_span); + break; + } + case ATTR_DOMAIN_EDGE: { + /* Not yet supported. */ + break; + } + default: { + BLI_assert_unreachable(); + break; + } + } +} + } // namespace blender::bke::mesh_surface_sample |