diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 1cc3f9aabfa..89194f19b9e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -31,7 +31,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 23 +#define BLENDER_FILE_SUBVERSION 24 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh index 88cba1bc15a..e16eec52cf2 100644 --- a/source/blender/blenkernel/BKE_geometry_fields.hh +++ b/source/blender/blenkernel/BKE_geometry_fields.hh @@ -375,11 +375,17 @@ class IDAttributeFieldInput : public GeometryFieldInput { VArray curve_normals_varray(const CurvesGeometry &curves, AttrDomain domain); -VArray mesh_normals_varray(const Mesh &mesh, const IndexMask &mask, AttrDomain domain); +VArray mesh_normals_varray(const Mesh &mesh, + const IndexMask &mask, + AttrDomain domain, + bool no_corner_normals = false); class NormalFieldInput : public GeometryFieldInput { + bool legacy_corner_normals_ = false; + public: - NormalFieldInput() : GeometryFieldInput(CPPType::get()) + NormalFieldInput(const bool legacy_corner_normals = false) + : GeometryFieldInput(CPPType::get()), legacy_corner_normals_(legacy_corner_normals) { category_ = Category::Generated; } diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0c90f68bb06..6b67721ea9f 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -122,7 +122,8 @@ void MeshComponent::count_memory(MemoryCounter &memory) const VArray mesh_normals_varray(const Mesh &mesh, const IndexMask &mask, - const AttrDomain domain) + const AttrDomain domain, + const bool no_corner_normals) { switch (domain) { case AttrDomain::Face: { @@ -148,12 +149,11 @@ VArray mesh_normals_varray(const Mesh &mesh, return VArray::ForContainer(std::move(edge_normals)); } case AttrDomain::Corner: { - /* The normals on corners are just the mesh's face normals, so start with the face normal - * array and copy the face normal for each of its corners. In this case using the mesh - * component's generic domain interpolation is fine, the data will still be normalized, - * since the face normal is just copied to every corner. */ - return mesh.attributes().adapt_domain( - VArray::ForSpan(mesh.face_normals()), AttrDomain::Face, AttrDomain::Corner); + if (no_corner_normals) { + return mesh.attributes().adapt_domain( + VArray::ForSpan(mesh.face_normals()), AttrDomain::Face, AttrDomain::Corner); + } + return VArray::ForSpan(mesh.corner_normals()); } default: return {}; diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc index a62a217dff5..482dde5f453 100644 --- a/source/blender/blenkernel/intern/geometry_fields.cc +++ b/source/blender/blenkernel/intern/geometry_fields.cc @@ -718,7 +718,7 @@ GVArray NormalFieldInput::get_varray_for_context(const GeometryFieldContext &con const IndexMask &mask) const { if (const Mesh *mesh = context.mesh()) { - return mesh_normals_varray(*mesh, mask, context.domain()); + return mesh_normals_varray(*mesh, mask, context.domain(), legacy_corner_normals_); } if (const CurvesGeometry *curves = context.curves_or_strokes()) { return curve_normals_varray(*curves, context.domain()); diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index cdc191bfff1..379705cc425 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -3591,6 +3591,17 @@ static void version_group_input_socket_data_block_reference(bNodeTree &ntree) } } +static void version_geometry_normal_input_node(bNodeTree &ntree) +{ + if (ntree.type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + if (STREQ(node->idname, "GeometryNodeInputNormal")) { + node->custom1 = 1; + } + } + } +} + void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) { @@ -5644,6 +5655,12 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 404, 24)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + version_geometry_normal_input_node(*ntree); + } + } + /* Always run this versioning; meshes are written with the legacy format which always needs to * be converted to the new format on file load. Can be moved to a subversion check in a larger * breaking release. */ diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 43ef380e8eb..d8bc8bc8203 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -10620,6 +10620,17 @@ static void def_geo_input_collection(BlenderRNA * /*brna*/, StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_input_normal(BlenderRNA * /*brna*/, StructRNA *srna) +{ + PropertyRNA *prop = RNA_def_property(srna, "legacy_corner_normals", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "custom1", 1); + RNA_def_property_ui_text( + prop, + "Flat Corner Normals", + "Always use face normals for the face corner domain, matching old behavior of the node"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_geo_input_object(BlenderRNA * /*brna*/, StructRNA *srna) { PropertyRNA *prop; @@ -12426,7 +12437,7 @@ static void rna_def_nodes(BlenderRNA *brna) define("GeometryNode", "GeometryNodeInputMeshVertexNeighbors"); define("GeometryNode", "GeometryNodeInputNamedAttribute"); define("GeometryNode", "GeometryNodeInputNamedLayerSelection"); - define("GeometryNode", "GeometryNodeInputNormal"); + define("GeometryNode", "GeometryNodeInputNormal", def_geo_input_normal); define("GeometryNode", "GeometryNodeInputObject", def_geo_input_object); define("GeometryNode", "GeometryNodeInputPosition"); define("GeometryNode", "GeometryNodeInputRadius"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc index 3d7443ed6fd..385491e317a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc @@ -4,6 +4,8 @@ #include "node_geometry_util.hh" +#include "UI_interface.hh" + namespace blender::nodes::node_geo_input_normal_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -11,9 +13,15 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output("Normal").field_source(); } +static void node_layout_ex(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) +{ + uiItemR(layout, ptr, "legacy_corner_normals", UI_ITEM_NONE, std::nullopt, ICON_NONE); +} + static void node_geo_exec(GeoNodeExecParams params) { - Field normal_field{std::make_shared()}; + const bool legacy_corner_normals = bool(params.node().custom1); + Field normal_field{std::make_shared(legacy_corner_normals)}; params.set_output("Normal", std::move(normal_field)); } @@ -30,6 +38,7 @@ static void node_register() ntype.nclass = NODE_CLASS_INPUT; ntype.geometry_node_execute = node_geo_exec; ntype.declare = node_declare; + ntype.draw_buttons_ex = node_layout_ex; blender::bke::node_register_type(&ntype); } NOD_REGISTER_NODE(node_register)