Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2021-06-17 11:31:53 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2021-06-17 23:11:32 +0300
commit4b673ebb990684af4a429d963a1026ddf3f2552f (patch)
treee5914b52a95fb60ed3ba3fcc63ceb71c3e2499ad /source/blender/blenkernel/intern/mesh_sample.cc
parent577d6d3f872206c99dc95c8afaff47ca0339d7fc (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.cc119
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