From 8100721dab8ad2c66762dad7332b359b3ae26210 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 22 Jun 2022 12:40:40 +0200 Subject: support translation --- release/scripts/startup/nodeitems_builtins.py | 2 +- source/blender/blenkernel/BKE_node.h | 2 +- source/blender/blenkernel/intern/node.cc | 2 +- source/blender/nodes/NOD_geometry.h | 2 +- source/blender/nodes/NOD_static_types.h | 2 +- source/blender/nodes/geometry/CMakeLists.txt | 2 +- .../nodes/node_geo_deform_curves_with_surface.cc | 168 ----------------- .../nodes/node_geo_sample_mesh_deformation.cc | 200 +++++++++++++++++++++ 8 files changed, 206 insertions(+), 174 deletions(-) delete mode 100644 source/blender/nodes/geometry/nodes/node_geo_deform_curves_with_surface.cc create mode 100644 source/blender/nodes/geometry/nodes/node_geo_sample_mesh_deformation.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index f4acc71a6da..1187927a9e8 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -80,7 +80,6 @@ def curve_node_items(context): yield NodeItem("GeometryNodeSampleCurve") yield NodeItem("GeometryNodeSubdivideCurve") yield NodeItem("GeometryNodeTrimCurve") - yield NodeItem("GeometryNodeDeformCurvesWithSurface") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputCurveHandlePositions") yield NodeItem("GeometryNodeInputTangent") @@ -114,6 +113,7 @@ def mesh_node_items(context): yield NodeItem("GeometryNodeMeshBoolean") yield NodeItem("GeometryNodeMeshToCurve") yield NodeItem("GeometryNodeMeshToPoints") + yield NodeItem("GeometryNodeSampleMeshDeformation") yield NodeItem("GeometryNodeSplitEdges") yield NodeItem("GeometryNodeSubdivideMesh") yield NodeItem("GeometryNodeSubdivisionSurface") diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 5917f9b88d7..e6bea7b23fe 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1496,7 +1496,7 @@ struct TexResult; #define GEO_NODE_INPUT_INSTANCE_ROTATION 1159 #define GEO_NODE_INPUT_INSTANCE_SCALE 1160 #define GEO_NODE_VOLUME_CUBE 1161 -#define GEO_NODE_DEFORM_CURVES_WITH_SURFACE 1162 +#define GEO_NODE_SAMPLE_MESH_DEFORMATION 1162 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index d4d14ca45be..7b7ad3fe4b4 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4749,7 +4749,6 @@ static void registerGeometryNodes() register_node_type_geo_curve_to_mesh(); register_node_type_geo_curve_to_points(); register_node_type_geo_curve_trim(); - register_node_type_geo_deform_curves_with_surface(); register_node_type_geo_delete_geometry(); register_node_type_geo_duplicate_elements(); register_node_type_geo_distribute_points_on_faces(); @@ -4812,6 +4811,7 @@ static void registerGeometryNodes() register_node_type_geo_realize_instances(); register_node_type_geo_remove_attribute(); register_node_type_geo_rotate_instances(); + register_node_type_geo_sample_mesh_deformation(); register_node_type_geo_scale_elements(); register_node_type_geo_scale_instances(); register_node_type_geo_separate_components(); diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index b9da2b17319..f0856e3b44a 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -47,7 +47,6 @@ void register_node_type_geo_curve_subdivide(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); void register_node_type_geo_curve_trim(void); -void register_node_type_geo_deform_curves_with_surface(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_duplicate_elements(void); void register_node_type_geo_distribute_points_on_faces(void); @@ -110,6 +109,7 @@ void register_node_type_geo_raycast(void); void register_node_type_geo_realize_instances(void); void register_node_type_geo_remove_attribute(void); void register_node_type_geo_rotate_instances(void); +void register_node_type_geo_sample_mesh_deformation(void); void register_node_type_geo_scale_elements(void); void register_node_type_geo_scale_instances(void); void register_node_type_geo_select_by_handle_type(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 54336ac65d0..ac78b75fe99 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -399,7 +399,7 @@ DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", Tri DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "") DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "") DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "") -DefNode(GeometryNode, GEO_NODE_DEFORM_CURVES_WITH_SURFACE, 0, "DEFORM_CURVES_WITH_SURFACE", DeformCurvesWithSurface, "Deform Curves with Surface", "") +DefNode(GeometryNode, GEO_NODE_SAMPLE_MESH_DEFORMATION, 0, "SAMPLE_MESH_DEFORMATION", SampleMeshDeformation, "Sample Mesh Deformation", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index fba13db0a49..02db28fd9d2 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -57,7 +57,6 @@ set(SRC nodes/node_geo_curve_to_mesh.cc nodes/node_geo_curve_to_points.cc nodes/node_geo_curve_trim.cc - nodes/node_geo_deform_curves_with_surface.cc nodes/node_geo_delete_geometry.cc nodes/node_geo_distribute_points_on_faces.cc nodes/node_geo_dual_mesh.cc @@ -120,6 +119,7 @@ set(SRC nodes/node_geo_realize_instances.cc nodes/node_geo_remove_attribute.cc nodes/node_geo_rotate_instances.cc + nodes/node_geo_sample_mesh_deformation.cc nodes/node_geo_scale_elements.cc nodes/node_geo_scale_instances.cc nodes/node_geo_separate_components.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_with_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_with_surface.cc deleted file mode 100644 index b3c7ec8fb9c..00000000000 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_with_surface.cc +++ /dev/null @@ -1,168 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "BKE_curves.hh" -#include "BKE_mesh_runtime.h" -#include "BKE_spline.hh" - -#include "BLI_task.hh" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "NOD_socket_search_link.hh" - -#include "node_geometry_util.hh" - -namespace blender::nodes::node_geo_deform_curves_with_surface_cc { - -using blender::attribute_math::mix2; - -NODE_STORAGE_FUNCS(NodeGeometryCurveTrim) - -static void node_declare(NodeDeclarationBuilder &b) -{ - b.add_input(N_("Curves")).supported_type(GEO_COMPONENT_TYPE_CURVE); - b.add_input(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); - b.add_input(N_("Rest Position")).hide_value().supports_field(); - b.add_output(N_("Curves")); -} - -static void node_layout(uiLayout *UNUSED(layout), bContext *UNUSED(C), PointerRNA *UNUSED(ptr)) -{ -} - -static void node_init(bNodeTree *UNUSED(tree), bNode *UNUSED(node)) -{ -} - -static void node_update(bNodeTree *UNUSED(ntree), bNode *UNUSED(node)) -{ -} - -static void deform_curves(const MeshComponent &mesh_component, - const Span rest_positions, - CurveComponent &curves_component) -{ - bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap( - curves_component.get_for_write()->geometry); - - const MutableSpan positions = curves.positions_for_write(); - const VArray surface_triangle_indices_varray = curves.surface_triangle_indices(); - if (surface_triangle_indices_varray.is_single() && - surface_triangle_indices_varray.get_internal_single() < 0) { - return; - } - const VArray_Span surface_triangle_indices{surface_triangle_indices_varray}; - const Span surface_triangle_coordinates = curves.surface_triangle_coords(); - if (surface_triangle_coordinates.is_empty()) { - return; - } - - const Mesh &mesh = *mesh_component.get_for_read(); - const Span looptris{BKE_mesh_runtime_looptri_ensure(&mesh), - BKE_mesh_runtime_looptri_len(&mesh)}; - - threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) { - for (const int curve_i : curves_range) { - const int looptri_i = surface_triangle_indices[curve_i]; - if (looptri_i < 0 || looptri_i >= looptris.size()) { - continue; - } - const IndexRange points = curves.points_for_curve(curve_i); - const int root_point_i = points[0]; - - const float3 bary_coord = bke::curves::decode_surface_bary_coord( - surface_triangle_coordinates[curve_i]); - const MLoopTri &looptri = looptris[looptri_i]; - const int v0 = mesh.mloop[looptri.tri[0]].v; - const int v1 = mesh.mloop[looptri.tri[1]].v; - const int v2 = mesh.mloop[looptri.tri[2]].v; - - const float3 &rest_v0 = rest_positions[v0]; - const float3 &rest_v1 = rest_positions[v1]; - const float3 &rest_v2 = rest_positions[v2]; - - const float3 &deformed_v0 = mesh.mvert[v0].co; - const float3 &deformed_v1 = mesh.mvert[v1].co; - const float3 &deformed_v2 = mesh.mvert[v2].co; - - float3 old_normal; - normal_tri_v3(old_normal, rest_v0, rest_v1, rest_v2); - float3 new_normal; - normal_tri_v3(new_normal, deformed_v0, deformed_v1, deformed_v2); - - /* TODO: Take tangend axis into account as well. */ - float rotation_mat[3][3]; - rotation_between_vecs_to_mat3(rotation_mat, old_normal, new_normal); - - const float3 old_curve_root = positions[root_point_i]; - const float3 old_surface_pos = attribute_math::mix3(bary_coord, rest_v0, rest_v1, rest_v2); - const float3 new_surface_pos = attribute_math::mix3( - bary_coord, deformed_v0, deformed_v1, deformed_v2); - const float3 root_pos_diff = new_surface_pos - old_surface_pos; - - for (const int point_i : points) { - const float3 old_pos = positions[point_i]; - const float3 old_relative_pos = old_pos - old_surface_pos; - float3 new_relative_pos = old_relative_pos; - mul_m3_v3(rotation_mat, new_relative_pos); - const float3 new_pos = new_surface_pos + new_relative_pos; - positions[point_i] = new_pos; - } - } - }); - - curves.tag_positions_changed(); -} - -static void node_geo_exec(GeoNodeExecParams params) -{ - GeometrySet curves_geometry = params.extract_input("Curves"); - GeometrySet mesh_geometry = params.extract_input("Mesh"); - Field rest_positions_field = params.extract_input>("Rest Position"); - - if (!mesh_geometry.has_mesh()) { - params.set_output("Curves", std::move(curves_geometry)); - return; - } - - const MeshComponent &mesh_component = *mesh_geometry.get_component_for_read(); - GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_POINT}; - FieldEvaluator field_evaluator{field_context, - mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT)}; - field_evaluator.add(rest_positions_field); - field_evaluator.evaluate(); - const VArray_Span rest_positions = field_evaluator.get_evaluated(0); - - curves_geometry.modify_geometry_sets([&](GeometrySet &curve_geometry) { - if (!curve_geometry.has_curves()) { - return; - } - CurveComponent &curves_component = curves_geometry.get_component_for_write(); - deform_curves(mesh_component, rest_positions, curves_component); - }); - - params.set_output("Curves", std::move(curves_geometry)); -} - -} // namespace blender::nodes::node_geo_deform_curves_with_surface_cc - -void register_node_type_geo_deform_curves_with_surface() -{ - namespace file_ns = blender::nodes::node_geo_deform_curves_with_surface_cc; - - static bNodeType ntype; - geo_node_type_base(&ntype, - GEO_NODE_DEFORM_CURVES_WITH_SURFACE, - "Deform Curves with Surface", - NODE_CLASS_GEOMETRY); - ntype.geometry_node_execute = file_ns::node_geo_exec; - ntype.draw_buttons = file_ns::node_layout; - ntype.declare = file_ns::node_declare; - node_type_init(&ntype, file_ns::node_init); - node_type_update(&ntype, file_ns::node_update); - nodeRegisterType(&ntype); -} diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_mesh_deformation.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_mesh_deformation.cc new file mode 100644 index 00000000000..ad39e77a810 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_mesh_deformation.cc @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_attribute_math.hh" +#include "BKE_curves.hh" +#include "BKE_mesh_runtime.h" +#include "BKE_type_conversions.hh" + +#include "BLI_task.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "NOD_socket_search_link.hh" + +#include "GEO_reverse_uv_sampler.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_sample_mesh_deformation_cc { + +using attribute_math::mix3; +using geometry::ReverseUVSampler; + +NODE_STORAGE_FUNCS(NodeGeometryCurveTrim) + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); + b.add_input(N_("Rest Position")).hide_value().supports_field(); + b.add_input(N_("UV Map")).hide_value().supports_field(); + b.add_input(N_("Sample UV")).supports_field(); + b.add_output(N_("Translation")).dependent_field({3}); + b.add_output(N_("Rotation")).dependent_field({3}); +} + +static void node_layout(uiLayout *UNUSED(layout), bContext *UNUSED(C), PointerRNA *UNUSED(ptr)) +{ +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *UNUSED(node)) +{ +} + +static void node_update(bNodeTree *UNUSED(ntree), bNode *UNUSED(node)) +{ +} + +class SampleMeshDeformationFunction : public fn::MultiFunction { + private: + GeometrySet geometry_; + const Mesh *mesh_; + Span verts_; + Array rest_positions_; + Array uv_map_; + std::optional reverse_uv_sampler; + + public: + SampleMeshDeformationFunction(GeometrySet geometry, + VArray rest_positions, + VArray uv_map) + : geometry_(std::move(geometry)), + rest_positions_(VArray_Span(rest_positions)), + uv_map_(VArray_Span(uv_map)) + { + mesh_ = geometry_.get_mesh_for_read(); + verts_ = Span(mesh_->mvert, mesh_->totvert); + const Span looptris{BKE_mesh_runtime_looptri_ensure(mesh_), + BKE_mesh_runtime_looptri_len(mesh_)}; + reverse_uv_sampler.emplace(uv_map_, looptris); + + static fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Sample Mesh Deformation"}; + signature.single_input("Sample UV"); + signature.single_output("Translation"); + signature.single_output("Rotation"); + return signature.build(); + } + + void call(const IndexMask mask, + fn::MFParams params, + fn::MFContext UNUSED(context)) const override + { + const VArray_Span sample_uvs = params.readonly_single_input(0, "Sample UV"); + MutableSpan r_translations = params.uninitialized_single_output_if_required( + 1, "Translation"); + MutableSpan r_rotations = params.uninitialized_single_output_if_required( + 2, "Rotation"); + + const bool compute_translation = !r_translations.is_empty(); + const bool compute_rotation = !r_rotations.is_empty(); + + for (const int i : mask) { + const float2 &sample_uv = sample_uvs[i]; + const ReverseUVSampler::Result sample_result = reverse_uv_sampler->sample(sample_uv); + if (sample_result.type != ReverseUVSampler::ResultType::Ok) { + if (compute_translation) { + r_translations[i] = float3(0.0f); + } + if (compute_rotation) { + r_rotations[i] = float3(0.0f); + } + continue; + } + + const MLoopTri &looptri = *sample_result.looptri; + const float3 &bary_weights = sample_result.bary_weights; + + const int corner_0 = looptri.tri[0]; + const int corner_1 = looptri.tri[1]; + const int corner_2 = looptri.tri[2]; + + const int vert_0 = mesh_->mloop[corner_0].v; + const int vert_1 = mesh_->mloop[corner_1].v; + const int vert_2 = mesh_->mloop[corner_2].v; + + const float3 &old_pos_0 = rest_positions_[corner_0]; + const float3 &old_pos_1 = rest_positions_[corner_1]; + const float3 &old_pos_2 = rest_positions_[corner_2]; + + const float3 &new_pos_0 = verts_[vert_0].co; + const float3 &new_pos_1 = verts_[vert_1].co; + const float3 &new_pos_2 = verts_[vert_2].co; + + if (compute_translation) { + const float3 old_pos = mix3(bary_weights, old_pos_0, old_pos_1, old_pos_2); + const float3 new_pos = mix3(bary_weights, new_pos_0, new_pos_1, new_pos_2); + const float3 translation = new_pos - old_pos; + r_translations[i] = translation; + } + if (compute_rotation) { + r_rotations[i] = float3(0.0f); + } + } + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry = params.extract_input("Mesh"); + Field rest_positions_field = params.extract_input>("Rest Position"); + Field uv_map_field = params.extract_input>("UV Map"); + Field sample_uv_field = params.extract_input>("Sample UV"); + + if (!geometry.has_mesh()) { + params.set_default_remaining_outputs(); + return; + } + + geometry.ensure_owns_direct_data(); + + const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); + + const MeshComponent &mesh_component = *geometry.get_component_for_read(); + GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_CORNER}; + FieldEvaluator field_evaluator{field_context, + mesh_component.attribute_domain_num(ATTR_DOMAIN_CORNER)}; + field_evaluator.add(rest_positions_field); + field_evaluator.add(conversions.try_convert(std::move(uv_map_field), CPPType::get())); + field_evaluator.evaluate(); + VArray rest_positions = field_evaluator.get_evaluated(0); + VArray uv_map = field_evaluator.get_evaluated(1); + + auto fn = std::make_unique( + std::move(geometry), std::move(rest_positions), std::move(uv_map)); + + Field sample_uv_field_float2 = conversions.try_convert(std::move(sample_uv_field), + CPPType::get()); + auto operation = std::make_shared( + std::move(fn), Vector{std::move(sample_uv_field_float2)}); + + params.set_output("Translation", Field(operation, 0)); + params.set_output("Rotation", Field(operation, 1)); + + params.set_default_remaining_outputs(); +} + +} // namespace blender::nodes::node_geo_sample_mesh_deformation_cc + +void register_node_type_geo_sample_mesh_deformation() +{ + namespace file_ns = blender::nodes::node_geo_sample_mesh_deformation_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_SAMPLE_MESH_DEFORMATION, "Sample Mesh Deformation", NODE_CLASS_GEOMETRY); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + nodeRegisterType(&ntype); +} -- cgit v1.2.3