Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
| Context not available. | |||||
| static void geo_node_raycast_declare(NodeDeclarationBuilder &b) | static void geo_node_raycast_declare(NodeDeclarationBuilder &b) | ||||
| { | { | ||||
| b.add_input<decl::Geometry>("Geometry"); | b.add_input<decl::Vector>("Source Position").implicit_field(); | ||||
| b.add_input<decl::Geometry>("Target Geometry"); | b.add_input<decl::Geometry>("Target Geometry"); | ||||
| b.add_input<decl::String>("Ray Direction"); | b.add_input<decl::Vector>("Ray Direction").default_value({0.0f, 0.0f, 1.0f}).supports_field(); | ||||
| b.add_input<decl::Vector>("Ray Direction", "Ray Direction_001") | b.add_input<decl::Float>("Ray Length") | ||||
| .default_value({0.0f, 0.0f, 1.0f}); | |||||
| b.add_input<decl::String>("Ray Length"); | |||||
| b.add_input<decl::Float>("Ray Length", "Ray Length_001") | |||||
| .default_value(100.0f) | .default_value(100.0f) | ||||
| .min(0.0f) | .min(0.0f) | ||||
| .subtype(PROP_DISTANCE); | .subtype(PROP_DISTANCE) | ||||
| b.add_input<decl::String>("Target Attribute"); | .supports_field(); | ||||
| b.add_input<decl::String>("Is Hit"); | |||||
| b.add_input<decl::String>("Hit Position"); | b.add_output<decl::Bool>("Is Hit").dependent_field(); | ||||
| b.add_input<decl::String>("Hit Normal"); | b.add_output<decl::Vector>("Hit Position").dependent_field(); | ||||
| b.add_input<decl::String>("Hit Distance"); | b.add_output<decl::Vector>("Hit Normal").dependent_field(); | ||||
| b.add_input<decl::String>("Hit Attribute"); | b.add_output<decl::Float>("Hit Distance").dependent_field(); | ||||
| b.add_output<decl::Geometry>("Geometry"); | |||||
| /* FOR TARGET ATTRIBUTE IF IMPLEMENTED*/ | |||||
| // b.add_output<decl::String>("Target Attribute"); | |||||
| // b.add_output<decl::String>("Hit Attribute"); | |||||
| } | } | ||||
| static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) | static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) | ||||
| Context not available. | |||||
| uiLayoutSetPropSep(layout, true); | uiLayoutSetPropSep(layout, true); | ||||
| uiLayoutSetPropDecorate(layout, false); | uiLayoutSetPropDecorate(layout, false); | ||||
| uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE); | 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 geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) | static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) | ||||
| { | { | ||||
| NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), | NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), | ||||
| __func__); | __func__); | ||||
| data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR; | data->mapping = GEO_NODE_RAYCAST_INTERPOLATED; | ||||
| data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; | |||||
| node->storage = data; | node->storage = data; | ||||
| } | } | ||||
| static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) | static void raycast_to_mesh(IndexMask mask, | ||||
| { | const Mesh &mesh, | ||||
| NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage; | |||||
| update_attribute_input_socket_availabilities( | |||||
| *node, | |||||
| "Ray Direction", | |||||
| (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction); | |||||
| update_attribute_input_socket_availabilities( | |||||
| *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_origins, | ||||
| const VArray<float3> &ray_directions, | const VArray<float3> &ray_directions, | ||||
| const VArray<float> &ray_lengths, | const VArray<float> &ray_lengths, | ||||
| const MutableSpan<bool> r_hit, | const MutableSpan<bool> &r_hit, | ||||
| const MutableSpan<int> r_hit_indices, | const MutableSpan<int> &r_hit_indices, | ||||
| const MutableSpan<float3> r_hit_positions, | const MutableSpan<float3> &r_hit_positions, | ||||
| const MutableSpan<float3> r_hit_normals, | const MutableSpan<float3> &r_hit_normals, | ||||
| const MutableSpan<float> r_hit_distances) | const MutableSpan<float> &r_hit_distances) | ||||
| { | { | ||||
| BLI_assert(ray_origins.size() == ray_directions.size()); | BLI_assert(ray_origins.size() == ray_directions.size()); | ||||
| BLI_assert(ray_origins.size() == ray_lengths.size()); | BLI_assert(ray_origins.size() == ray_lengths.size()); | ||||
| Context not available. | |||||
| return; | return; | ||||
| } | } | ||||
| for (const int i : ray_origins.index_range()) { | for (const int i : mask) { | ||||
| const float ray_length = ray_lengths[i]; | const float ray_length = ray_lengths[i]; | ||||
| const float3 ray_origin = ray_origins[i]; | const float3 ray_origin = ray_origins[i]; | ||||
| const float3 ray_direction = ray_directions[i].normalized(); | const float3 ray_direction = ray_directions[i].normalized(); | ||||
| Context not available. | |||||
| free_bvhtree_from_mesh(&tree_data); | free_bvhtree_from_mesh(&tree_data); | ||||
| } | } | ||||
| static bke::mesh_surface_sample::eAttributeMapMode get_map_mode( | static void raycast_from_points(IndexMask mask, | ||||
| GeometryNodeRaycastMapMode map_mode) | const VArray<float3> &ray_origins, | ||||
| { | const VArray<float3> &ray_directions, | ||||
| switch (map_mode) { | const VArray<float> &ray_lengths, | ||||
| 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 ¶ms, | |||||
| const GeometrySet &target_geometry, | const GeometrySet &target_geometry, | ||||
| GeometryComponent &dst_component, | /*UNUSED FOR NOW MAY NEED FOR TARGET ATTRIBUTE NODE*/ | ||||
| const StringRef hit_name, | const GeometryNodeRaycastMapMode map_mode, | ||||
| const StringRef hit_position_name, | MutableSpan<bool> r_is_hits, | ||||
| const StringRef hit_normal_name, | MutableSpan<float3> r_hit_positions, | ||||
| const StringRef hit_distance_name, | MutableSpan<float3> r_hit_normals, | ||||
| const Span<std::string> hit_attribute_names, | MutableSpan<float> r_hit_distances) | ||||
| const Span<std::string> hit_attribute_output_names) | |||||
| { | { | ||||
| BLI_assert(hit_attribute_names.size() == hit_attribute_output_names.size()); | |||||
| const MeshComponent *src_mesh_component = | const MeshComponent *src_mesh_component = | ||||
| target_geometry.get_component_for_read<MeshComponent>(); | target_geometry.get_component_for_read<MeshComponent>(); | ||||
| if (src_mesh_component == nullptr) { | if (src_mesh_component == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| Context not available. | |||||
| return; | 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; | |||||
| GVArray_Typed<float3> ray_origins = dst_component.attribute_get_for_read<float3>( | |||||
| "position", result_domain, {0, 0, 0}); | |||||
| GVArray_Typed<float3> ray_directions = params.get_input_attribute<float3>( | |||||
| "Ray Direction", dst_component, result_domain, {0, 0, 0}); | |||||
| GVArray_Typed<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<int> hit_indices; | ||||
| Array<float3> hit_positions_internal; | Array<float3> hit_positions_internal; | ||||
| if (!hit_attribute_names.is_empty()) { | |||||
| hit_indices.reinitialize(ray_origins->size()); | |||||
| if (!hit_position_attribute) { | raycast_to_mesh(mask, | ||||
| hit_positions_internal.reinitialize(ray_origins->size()); | *src_mesh, | ||||
| } | |||||
| } | |||||
| 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_origins, | ||||
| ray_directions, | ray_directions, | ||||
| ray_lengths, | ray_lengths, | ||||
| is_hit, | r_is_hits, | ||||
| hit_indices, | hit_indices, | ||||
| hit_positions, | r_hit_positions, | ||||
| hit_normals, | r_hit_normals, | ||||
| hit_distances); | r_hit_distances); | ||||
| hit_attribute.save(); | /* THIS IS THE ORIGINAL CODE FOR TARGET ATTRIBUTE */ | ||||
| hit_position_attribute.save(); | |||||
| hit_normal_attribute.save(); | // const AttributeDomain result_domain = ATTR_DOMAIN_POINT; | ||||
| hit_distance_attribute.save(); | |||||
| // /* Custom interpolated attributes */ | |||||
| /* Custom interpolated attributes */ | // bke::mesh_surface_sample::MeshAttributeInterpolator interp(src_mesh, hit_positions, | ||||
| bke::mesh_surface_sample::MeshAttributeInterpolator interp(src_mesh, hit_positions, hit_indices); | // hit_indices); for (const int i : hit_attribute_names.index_range()) { | ||||
| for (const int i : hit_attribute_names.index_range()) { | // const std::optional<AttributeMetaData> meta_data = | ||||
| const std::optional<AttributeMetaData> meta_data = src_mesh_component->attribute_get_meta_data( | // src_mesh_component->attribute_get_meta_data( | ||||
| hit_attribute_names[i]); | // hit_attribute_names[i]); | ||||
| if (meta_data) { | // if (meta_data) { | ||||
| ReadAttributeLookup hit_attribute = src_mesh_component->attribute_try_get_for_read( | // ReadAttributeLookup hit_attribute = src_mesh_component->attribute_try_get_for_read( | ||||
| hit_attribute_names[i]); | // hit_attribute_names[i]); | ||||
| OutputAttribute hit_attribute_output = dst_component.attribute_try_get_for_output_only( | // OutputAttribute hit_attribute_output = dst_component.attribute_try_get_for_output_only( | ||||
| hit_attribute_output_names[i], result_domain, meta_data->data_type); | // hit_attribute_output_names[i], result_domain, meta_data->data_type); | ||||
| interp.sample_attribute(hit_attribute, hit_attribute_output, map_mode); | // interp.sample_attribute(hit_attribute, hit_attribute_output, map_mode); | ||||
| hit_attribute_output.save(); | // hit_attribute_output.save(); | ||||
| } | // } | ||||
| } | // } | ||||
| } | } | ||||
| class RaycastFunction : public fn::MultiFunction { | |||||
| private: | |||||
| GeometrySet target_; | |||||
| GeometryNodeRaycastMapMode mode_; | |||||
| public: | |||||
| RaycastFunction(GeometrySet target, GeometryNodeRaycastMapMode mode) | |||||
| : target_(std::move(target)), mode_((GeometryNodeRaycastMapMode)mode) | |||||
| { | |||||
| static fn::MFSignature signature = create_signature(); | |||||
| this->set_signature(&signature); | |||||
| } | |||||
| static fn::MFSignature create_signature() | |||||
| { | |||||
| blender::fn::MFSignatureBuilder signature{"Geometry Proximity"}; | |||||
| signature.single_input<float3>("Source Position"); | |||||
| signature.single_input<float3>("Ray Direction"); | |||||
| signature.single_input<float>("Ray Length"); | |||||
| signature.single_output<bool>("Is Hit"); | |||||
| signature.single_output<float3>("Hit Position"); | |||||
| signature.single_output<float3>("Hit Normal"); | |||||
| signature.single_output<float>("Distance"); | |||||
| return signature.build(); | |||||
| } | |||||
| void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override | |||||
| { | |||||
| const VArray<float3> &in_positions = params.readonly_single_input<float3>(0, | |||||
| "Source Position"); | |||||
| const VArray<float3> &in_directions = params.readonly_single_input<float3>(1, "Ray Direction"); | |||||
| const VArray<float> &in_lengths = params.readonly_single_input<float>(2, "Ray Length"); | |||||
| MutableSpan<bool> is_hits = params.uninitialized_single_output<bool>(3, "Is Hit"); | |||||
| MutableSpan<float3> hit_positions = params.uninitialized_single_output<float3>(4, | |||||
| "Hit Position"); | |||||
| MutableSpan<float3> hit_normals = params.uninitialized_single_output<float3>(5, "Hit Normal"); | |||||
| MutableSpan<float> hit_distances = params.uninitialized_single_output<float>(6, "Distance"); | |||||
| raycast_from_points(mask, | |||||
| in_positions, | |||||
| in_directions, | |||||
| in_lengths, | |||||
| target_, | |||||
| mode_, | |||||
| is_hits, | |||||
| hit_positions, | |||||
| hit_normals, | |||||
| hit_distances); | |||||
| } | |||||
| }; | |||||
| static void geo_node_raycast_exec(GeoNodeExecParams params) | static void geo_node_raycast_exec(GeoNodeExecParams params) | ||||
| { | { | ||||
| GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); | |||||
| GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry"); | GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry"); | ||||
| target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set); | |||||
| const std::string hit_name = params.extract_input<std::string>("Is Hit"); | if (!target_geometry_set.has_mesh() && !target_geometry_set.has_pointcloud() && | ||||
| const std::string hit_position_name = params.extract_input<std::string>("Hit Position"); | !target_geometry_set.has_curve()) { | ||||
| const std::string hit_normal_name = params.extract_input<std::string>("Hit Normal"); | params.set_output("Is Hit", fn::make_constant_field<bool>(false)); | ||||
| const std::string hit_distance_name = params.extract_input<std::string>("Hit Distance"); | params.set_output("Hit Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); | ||||
| params.set_output("Hit Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); | |||||
| params.set_output("Hit Distance", fn::make_constant_field<float>(0.0f)); | |||||
| return; | |||||
| } | |||||
| const Array<std::string> hit_names = {params.extract_input<std::string>("Target Attribute")}; | Field<float3> position_field = params.extract_input<Field<float3>>("Source Position"); | ||||
| const Array<std::string> hit_output_names = {params.extract_input<std::string>("Hit Attribute")}; | Field<float3> direction_field = params.extract_input<Field<float3>>("Ray Direction"); | ||||
| Field<float> length_field = params.extract_input<Field<float>>("Ray Length"); | |||||
| geometry_set = bke::geometry_set_realize_instances(geometry_set); | const NodeGeometryRaycast &storage = *(const NodeGeometryRaycast *)params.node().storage; | ||||
| target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set); | |||||
| static const Array<GeometryComponentType> types = { | auto raycast_fn = std::make_unique<RaycastFunction>(std::move(target_geometry_set), | ||||
| GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; | (GeometryNodeRaycastMapMode)storage.mapping); | ||||
| for (const GeometryComponentType type : types) { | auto raycast_op = std::make_shared<FieldOperation>(FieldOperation( | ||||
| if (geometry_set.has(type)) { | std::move(raycast_fn), | ||||
| raycast_from_points(params, | {std::move(position_field), std::move(direction_field), std::move(length_field)})); | ||||
| 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); | params.set_output("Is Hit", Field<bool>(raycast_op, 0)); | ||||
| params.set_output("Hit Position", Field<float3>(raycast_op, 1)); | |||||
| params.set_output("Hit Normal", Field<float3>(raycast_op, 2)); | |||||
| params.set_output("Hit Distance", Field<float>(raycast_op, 3)); | |||||
| } | } | ||||
| } // namespace blender::nodes | } // namespace blender::nodes | ||||
| void register_node_type_geo_raycast() | void register_node_type_geo_legacy_raycast() | ||||
| { | { | ||||
| static bNodeType ntype; | static bNodeType ntype; | ||||
| geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); | geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); | ||||
| node_type_size_preset(&ntype, NODE_SIZE_LARGE); | node_type_size_preset(&ntype, NODE_SIZE_LARGE); | ||||
| node_type_init(&ntype, blender::nodes::geo_node_raycast_init); | node_type_init(&ntype, blender::nodes::geo_node_raycast_init); | ||||
| node_type_update(&ntype, blender::nodes::geo_node_raycast_update); | |||||
| node_type_storage( | node_type_storage( | ||||
| &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); | &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); | ||||
| ntype.declare = blender::nodes::geo_node_raycast_declare; | ntype.declare = blender::nodes::geo_node_raycast_declare; | ||||
| Context not available. | |||||