From 4b673ebb990684af4a429d963a1026ddf3f2552f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 17 Jun 2021 09:31:53 +0100 Subject: 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 --- source/blender/blenkernel/intern/mesh_sample.cc | 119 +++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/mesh_sample.cc') 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 get_mesh_looptris(const Mesh &mesh) +Span 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)); @@ -155,4 +156,120 @@ void sample_face_attribute(const Mesh &mesh, }); } +MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh, + const Span positions, + const Span looptri_indices) + : mesh_(mesh), positions_(positions), looptri_indices_(looptri_indices) +{ + BLI_assert(positions.size() == looptri_indices.size()); +} + +Span 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 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 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 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 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 -- cgit v1.2.3