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:
Diffstat (limited to 'source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc')
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc328
1 files changed, 328 insertions, 0 deletions
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
new file mode 100644
index 00000000000..599ffd617a5
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -0,0 +1,328 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_sample.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_legacy_raycast_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Target Geometry"));
+ b.add_input<decl::String>(N_("Ray Direction"));
+ b.add_input<decl::Vector>(N_("Ray Direction"), "Ray Direction_001")
+ .default_value({0.0f, 0.0f, 1.0f});
+ b.add_input<decl::String>(N_("Ray Length"));
+ b.add_input<decl::Float>(N_("Ray Length"), "Ray Length_001")
+ .default_value(100.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::String>(N_("Target Attribute"));
+ b.add_input<decl::String>(N_("Is Hit"));
+ b.add_input<decl::String>(N_("Hit Position"));
+ b.add_input<decl::String>(N_("Hit Normal"));
+ b.add_input<decl::String>(N_("Hit Distance"));
+ b.add_input<decl::String>(N_("Hit Attribute"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
+ uiItemR(layout, ptr, "input_type_ray_direction", 0, IFACE_("Ray Direction"), ICON_NONE);
+ uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
+ __func__);
+ data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
+ data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage;
+ update_attribute_input_socket_availabilities(
+ *ntree,
+ *node,
+ "Ray Direction",
+ (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction);
+ update_attribute_input_socket_availabilities(
+ *ntree,
+ *node,
+ "Ray Length",
+ (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length);
+}
+
+static void raycast_to_mesh(const Mesh &mesh,
+ const VArray<float3> &ray_origins,
+ const VArray<float3> &ray_directions,
+ const VArray<float> &ray_lengths,
+ const MutableSpan<bool> r_hit,
+ const MutableSpan<int> r_hit_indices,
+ const MutableSpan<float3> r_hit_positions,
+ const MutableSpan<float3> r_hit_normals,
+ const MutableSpan<float> r_hit_distances)
+{
+ BLI_assert(ray_origins.size() == ray_directions.size());
+ BLI_assert(ray_origins.size() == ray_lengths.size());
+ BLI_assert(ray_origins.size() == r_hit.size() || r_hit.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_indices.size() || r_hit_indices.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_positions.size() || r_hit_positions.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_normals.size() || r_hit_normals.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_distances.size() || r_hit_distances.is_empty());
+
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 4);
+ if (tree_data.tree == nullptr) {
+ free_bvhtree_from_mesh(&tree_data);
+ return;
+ }
+
+ for (const int i : ray_origins.index_range()) {
+ const float ray_length = ray_lengths[i];
+ const float3 ray_origin = ray_origins[i];
+ const float3 ray_direction = ray_directions[i].normalized();
+
+ BVHTreeRayHit hit;
+ hit.index = -1;
+ hit.dist = ray_length;
+ if (BLI_bvhtree_ray_cast(tree_data.tree,
+ ray_origin,
+ ray_direction,
+ 0.0f,
+ &hit,
+ tree_data.raycast_callback,
+ &tree_data) != -1) {
+ if (!r_hit.is_empty()) {
+ r_hit[i] = hit.index >= 0;
+ }
+ if (!r_hit_indices.is_empty()) {
+ /* Index should always be a valid looptri index, use 0 when hit failed. */
+ r_hit_indices[i] = max_ii(hit.index, 0);
+ }
+ if (!r_hit_positions.is_empty()) {
+ r_hit_positions[i] = hit.co;
+ }
+ if (!r_hit_normals.is_empty()) {
+ r_hit_normals[i] = hit.no;
+ }
+ if (!r_hit_distances.is_empty()) {
+ r_hit_distances[i] = hit.dist;
+ }
+ }
+ else {
+ if (!r_hit.is_empty()) {
+ r_hit[i] = false;
+ }
+ if (!r_hit_indices.is_empty()) {
+ r_hit_indices[i] = 0;
+ }
+ if (!r_hit_positions.is_empty()) {
+ r_hit_positions[i] = float3(0.0f, 0.0f, 0.0f);
+ }
+ if (!r_hit_normals.is_empty()) {
+ r_hit_normals[i] = float3(0.0f, 0.0f, 0.0f);
+ }
+ if (!r_hit_distances.is_empty()) {
+ r_hit_distances[i] = ray_length;
+ }
+ }
+ }
+
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static bke::mesh_surface_sample::eAttributeMapMode get_map_mode(
+ GeometryNodeRaycastMapMode map_mode)
+{
+ switch (map_mode) {
+ case GEO_NODE_RAYCAST_INTERPOLATED:
+ return bke::mesh_surface_sample::eAttributeMapMode::INTERPOLATED;
+ default:
+ case GEO_NODE_RAYCAST_NEAREST:
+ return bke::mesh_surface_sample::eAttributeMapMode::NEAREST;
+ }
+}
+
+static void raycast_from_points(const GeoNodeExecParams &params,
+ const GeometrySet &target_geometry,
+ GeometryComponent &dst_component,
+ const StringRef hit_name,
+ const StringRef hit_position_name,
+ const StringRef hit_normal_name,
+ const StringRef hit_distance_name,
+ const Span<std::string> hit_attribute_names,
+ const Span<std::string> hit_attribute_output_names)
+{
+ BLI_assert(hit_attribute_names.size() == hit_attribute_output_names.size());
+
+ const MeshComponent *src_mesh_component =
+ target_geometry.get_component_for_read<MeshComponent>();
+ if (src_mesh_component == nullptr) {
+ return;
+ }
+ const Mesh *src_mesh = src_mesh_component->get_for_read();
+ if (src_mesh == nullptr) {
+ return;
+ }
+ if (src_mesh->totpoly == 0) {
+ return;
+ }
+
+ const NodeGeometryRaycast &storage = *(const NodeGeometryRaycast *)params.node().storage;
+ bke::mesh_surface_sample::eAttributeMapMode map_mode = get_map_mode(
+ (GeometryNodeRaycastMapMode)storage.mapping);
+ const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+
+ VArray<float3> ray_origins = dst_component.attribute_get_for_read<float3>(
+ "position", result_domain, {0, 0, 0});
+ VArray<float3> ray_directions = params.get_input_attribute<float3>(
+ "Ray Direction", dst_component, result_domain, {0, 0, 0});
+ VArray<float> ray_lengths = params.get_input_attribute<float>(
+ "Ray Length", dst_component, result_domain, 0);
+
+ OutputAttribute_Typed<bool> hit_attribute =
+ dst_component.attribute_try_get_for_output_only<bool>(hit_name, result_domain);
+ OutputAttribute_Typed<float3> hit_position_attribute =
+ dst_component.attribute_try_get_for_output_only<float3>(hit_position_name, result_domain);
+ OutputAttribute_Typed<float3> hit_normal_attribute =
+ dst_component.attribute_try_get_for_output_only<float3>(hit_normal_name, result_domain);
+ OutputAttribute_Typed<float> hit_distance_attribute =
+ dst_component.attribute_try_get_for_output_only<float>(hit_distance_name, result_domain);
+
+ /* Positions and looptri indices are always needed for interpolation,
+ * so create temporary arrays if no output attribute is given. */
+ Array<int> hit_indices;
+ Array<float3> hit_positions_internal;
+ if (!hit_attribute_names.is_empty()) {
+ hit_indices.reinitialize(ray_origins.size());
+
+ if (!hit_position_attribute) {
+ hit_positions_internal.reinitialize(ray_origins.size());
+ }
+ }
+ const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>();
+ const MutableSpan<float3> hit_positions = hit_position_attribute ?
+ hit_position_attribute.as_span() :
+ hit_positions_internal;
+ const MutableSpan<float3> hit_normals = hit_normal_attribute ? hit_normal_attribute.as_span() :
+ MutableSpan<float3>();
+ const MutableSpan<float> hit_distances = hit_distance_attribute ?
+ hit_distance_attribute.as_span() :
+ MutableSpan<float>();
+
+ raycast_to_mesh(*src_mesh,
+ ray_origins,
+ ray_directions,
+ ray_lengths,
+ is_hit,
+ hit_indices,
+ hit_positions,
+ hit_normals,
+ hit_distances);
+
+ hit_attribute.save();
+ hit_position_attribute.save();
+ hit_normal_attribute.save();
+ hit_distance_attribute.save();
+
+ /* Custom interpolated attributes */
+ bke::mesh_surface_sample::MeshAttributeInterpolator interp(
+ src_mesh, IndexMask(ray_origins.size()), hit_positions, hit_indices);
+ for (const int i : hit_attribute_names.index_range()) {
+ const std::optional<AttributeMetaData> meta_data = src_mesh_component->attribute_get_meta_data(
+ hit_attribute_names[i]);
+ if (meta_data) {
+ ReadAttributeLookup hit_attribute = src_mesh_component->attribute_try_get_for_read(
+ hit_attribute_names[i]);
+ OutputAttribute hit_attribute_output = dst_component.attribute_try_get_for_output_only(
+ hit_attribute_output_names[i], result_domain, meta_data->data_type);
+
+ interp.sample_attribute(hit_attribute, hit_attribute_output, map_mode);
+
+ hit_attribute_output.save();
+ }
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry");
+
+ const std::string hit_name = params.extract_input<std::string>("Is Hit");
+ const std::string hit_position_name = params.extract_input<std::string>("Hit Position");
+ const std::string hit_normal_name = params.extract_input<std::string>("Hit Normal");
+ const std::string hit_distance_name = params.extract_input<std::string>("Hit Distance");
+
+ const Array<std::string> hit_names = {params.extract_input<std::string>("Target Attribute")};
+ const Array<std::string> hit_output_names = {params.extract_input<std::string>("Hit Attribute")};
+
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
+ target_geometry_set = geometry::realize_instances_legacy(target_geometry_set);
+
+ static const Array<GeometryComponentType> types = {
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+ for (const GeometryComponentType type : types) {
+ if (geometry_set.has(type)) {
+ raycast_from_points(params,
+ target_geometry_set,
+ geometry_set.get_component_for_write(type),
+ hit_name,
+ hit_position_name,
+ hit_normal_name,
+ hit_distance_name,
+ hit_names,
+ hit_output_names);
+ }
+ }
+
+ params.set_output("Geometry", geometry_set);
+}
+
+} // namespace blender::nodes::node_geo_legacy_raycast_cc
+
+void register_node_type_geo_legacy_raycast()
+{
+ namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_storage(
+ &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}