diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/geometry/intern/solidify_nonmanifold.c | 62 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 30 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_solidify.cc | 241 |
5 files changed, 184 insertions, 151 deletions
diff --git a/source/blender/geometry/intern/solidify_nonmanifold.c b/source/blender/geometry/intern/solidify_nonmanifold.c index 936c7f157b2..5d08648e17c 100644 --- a/source/blender/geometry/intern/solidify_nonmanifold.c +++ b/source/blender/geometry/intern/solidify_nonmanifold.c @@ -140,12 +140,14 @@ static int comp_float_int_pair(const void *a, const void *b) } /* NOLINTNEXTLINE: readability-function-size */ -Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *mesh) +Mesh *solidify_nonmanifold(const SolidifyData *solidify_data, + Mesh *mesh, + bool **r_shell_verts, + bool **r_rim_verts, + bool **r_shell_faces, + bool **r_rim_faces) { Mesh *result; - const SolidifyModifierData *smd = (SolidifyModifierData *)md; MVert *mv, *mvert, *orig_mvert; MEdge *ed, *medge, *orig_medge; @@ -154,39 +156,28 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, const uint numVerts = (uint)mesh->totvert; const uint numEdges = (uint)mesh->totedge; const uint numPolys = (uint)mesh->totpoly; + const uint numLoops = (uint)mesh->totloop; if (numPolys == 0 && numVerts != 0) { return mesh; } - /* Only use material offsets if we have 2 or more materials. */ - const short mat_nrs = ctx->object->totcol > 1 ? ctx->object->totcol : 1; - const short mat_nr_max = mat_nrs - 1; - const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0; - const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0; - - /* #ofs_front and #ofs_back are the offset from the original - * surface along the normal, where #oft_front is along the positive - * and #oft_back is along the negative normal. */ - const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset; - const float ofs_back = ofs_front - smd->offset * smd->offset_fac; - /* #ofs_front_clamped and #ofs_back_clamped are the same as - * #ofs_front and #ofs_back, but never zero. */ - const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f); - const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f); - const float offset_fac_vg = smd->offset_fac_vg; - const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; - const float offset = fabsf(smd->offset) * smd->offset_clamp; - const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP; - /* #do_flip, flips the normals of the result. This is inverted if negative thickness - * is used, since simple solidify with negative thickness keeps the faces facing outside. */ - const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0); - const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM; - const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == - 0; - const bool do_clamp = (smd->offset_clamp != 0.0f); - - const float bevel_convex = smd->bevel_convex; + float(*poly_nors)[3] = NULL; + + const float ofs_front = (solidify_data->offset_fac + 1.0f) * 0.5f * solidify_data->offset; + const float ofs_back = ofs_front - solidify_data->offset * solidify_data->offset_fac; + const float ofs_front_clamped = max_ff(1e-5f, + fabsf(solidify_data->offset > 0 ? ofs_front : ofs_back)); + const float ofs_back_clamped = max_ff(1e-5f, + fabsf(solidify_data->offset > 0 ? ofs_back : ofs_front)); + const float offset_fac_vg = solidify_data->offset_fac_vg; + const float offset_fac_vg_inv = 1.0f - solidify_data->offset_fac_vg; + const float offset = fabsf(solidify_data->offset) * solidify_data->offset_clamp; + const bool do_angle_clamp = solidify_data->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP; + const bool do_flip = (solidify_data->flag & MOD_SOLIDIFY_FLIP) != 0; + const bool do_rim = solidify_data->flag & MOD_SOLIDIFY_RIM; + const bool do_shell = solidify_data->flag & MOD_SOLIDIFY_SHELL; + const bool do_clamp = (solidify_data->offset_clamp != 0.0f); const float bevel_convex = solidify_data->bevel_convex; @@ -204,9 +195,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, #define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1) - /* Calculate only face normals. Copied because they are modified directly below. */ - float(*poly_nors)[3] = MEM_malloc_arrayN(numPolys, sizeof(float[3]), __func__); - memcpy(poly_nors, BKE_mesh_poly_normals_ensure(mesh), sizeof(float[3]) * numPolys); + /* Calculate only face normals. */ + poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); + BKE_mesh_calc_normals_poly( + orig_mvert, (int)numVerts, orig_mloop, (int)numLoops, orig_mpoly, (int)numPolys, poly_nors); NewFaceRef *face_sides_arr = MEM_malloc_arrayN( numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 86bae61258c..57624a4a0cd 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -10485,6 +10485,36 @@ static void def_geo_point_scale(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static const EnumPropertyItem nonmanifold_thickness_mode_items[] = { + {MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_FIXED, + "FIXED", + 0, + "Fixed", + "Most basic thickness calculation"}, + {MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN, + "EVEN", + 0, + "Even", + "Even thickness calculation which takes the angle between faces into account"}, + {MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS, + "CONSTRAINTS", + 0, + "Constraints", + "Thickness calculation using constraints, most advanced"}, + {0, NULL, 0, NULL, NULL}, +}; + +static const EnumPropertyItem nonmanifold_boundary_mode_items[] = { + {MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE, "NONE", 0, "None", "No shape correction"}, + {MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_ROUND, + "ROUND", + 0, + "Round", + "Round open perimeter shape"}, + {MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT, "FLAT", 0, "Flat", "Flat open perimeter shape"}, + {0, NULL, 0, NULL, NULL}, +}; + static void def_geo_solidify(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index d41d294a371..816e492bc49 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -434,7 +434,6 @@ DefNode(GeometryNode, GEO_NODE_STRING_TO_CURVES, def_geo_string_to_curves, "STRI DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideCurve, "Subdivide Curve", "") DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_MESH, 0, "SUBDIVIDE_MESH", SubdivideMesh, "Subdivide Mesh", "") DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") -DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "") DefNode(GeometryNode, GEO_NODE_TRANSFER_ATTRIBUTE, def_geo_transfer_attribute, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Transfer Attribute", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 2a8faf65a6d..a8ad9d3e0e4 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -184,6 +184,7 @@ set(SRC nodes/node_geo_set_shade_smooth.cc nodes/node_geo_set_spline_cyclic.cc nodes/node_geo_set_spline_resolution.cc + nodes/node_geo_solidify.cc nodes/node_geo_string_join.cc nodes/node_geo_string_to_curves.cc nodes/node_geo_subdivision_surface.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_solidify.cc b/source/blender/nodes/geometry/nodes/node_geo_solidify.cc index 197aa0a09c1..41448a37d34 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_solidify.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_solidify.cc @@ -27,31 +27,36 @@ #include "node_geometry_util.hh" -static bNodeSocketTemplate geo_node_solidify_in[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_STRING, N_("Thickness")}, - {SOCK_FLOAT, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, - {SOCK_FLOAT, N_("Clamp"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR}, - {SOCK_FLOAT, N_("Offset"), -1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR}, - {SOCK_BOOLEAN, N_("Fill"), true}, - {SOCK_BOOLEAN, N_("Rim"), true}, - {SOCK_STRING, N_("Fill Faces")}, - {SOCK_STRING, N_("Rim Faces")}, - {-1, ""}, -}; - -static bNodeSocketTemplate geo_node_solidify_out[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {-1, ""}, -}; - -namespace blender::nodes { - -static void geo_node_solidify_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +namespace blender::nodes::node_geo_solidify { +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); + b.add_input<decl::Float>(N_("Thickness")) + .default_value(0.0f) + .subtype(PROP_DISTANCE) + .supports_field(); + b.add_input<decl::Float>(N_("Clamp")) + .default_value(0.0f) + .min(0.0f) + .max(2.0f) + .subtype(PROP_FACTOR); + b.add_input<decl::Float>(N_("Offset")) + .default_value(0.0f) + .min(-1.0f) + .max(1.0f) + .subtype(PROP_FACTOR); + b.add_input<decl::Bool>(N_("Fill")).default_value(true); + b.add_input<decl::Bool>(N_("Rim")).default_value(true); + + b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Fill Faces")).field_source(); + b.add_output<decl::Bool>(N_("Rim Faces")).field_source(); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "thickness_mode", 0, nullptr, ICON_NONE); uiItemR(layout, ptr, "nonmanifold_offset_mode", 0, nullptr, ICON_NONE); uiItemR(layout, ptr, "nonmanifold_boundary_mode", 0, nullptr, ICON_NONE); } @@ -62,126 +67,132 @@ static void geo_node_solidify_init(bNodeTree *UNUSED(tree), bNode *node) sizeof(NodeGeometrySolidify), __func__); node->storage = node_storage; - node_storage->thickness_mode = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; -} - -static void geo_node_solidify_update(bNodeTree *UNUSED(ntree), bNode *node) -{ - const NodeGeometrySolidify *node_storage = (NodeGeometrySolidify *)node->storage; - - update_attribute_input_socket_availabilities( - *node, "Thickness", (GeometryNodeAttributeInputMode)node_storage->thickness_mode, true); } -static void geo_node_solidify_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); NodeGeometrySolidify &node_storage = *(NodeGeometrySolidify *)node.storage; const Object *self_object = params.self_object(); - GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); bool add_fill = params.extract_input<bool>("Fill"); bool add_rim = params.extract_input<bool>("Rim"); - - char flag = 0; - - if (add_fill) { - flag |= MOD_SOLIDIFY_SHELL; - } - - if (add_rim) { - flag |= MOD_SOLIDIFY_RIM; - } + GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); float offset = params.extract_input<float>("Offset"); float offset_clamp = params.extract_input<float>("Clamp"); - geometry_set = geometry_set_realize_instances(geometry_set); + bke::StrongAnonymousAttributeID fill_id; + bke::StrongAnonymousAttributeID rim_id; if (geometry_set.has<MeshComponent>()) { - MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - Mesh *input_mesh = mesh_component.get_for_write(); - - const float default_thickness = 0; - GVArray_Typed<float> thickness_attribute = params.get_input_attribute<float>( - - "Thickness", mesh_component, ATTR_DOMAIN_POINT, default_thickness); - VArray_Span<float> thickness{thickness_attribute}; - - SolidifyData solidify_node_data = { - self_object, - 1, - offset, - 0.0f, - offset_clamp, - node_storage.nonmanifold_offset_mode, - node_storage.nonmanifold_boundary_mode, - flag, - 0.01f, - 0.0f, - thickness.data(), - }; - - bool *shell_verts = nullptr; - bool *rim_verts = nullptr; - bool *shell_faces = nullptr; - bool *rim_faces = nullptr; - - Mesh *output_mesh = solidify_nonmanifold( - &solidify_node_data, input_mesh, &shell_verts, &rim_verts, &shell_faces, &rim_faces); - - if (output_mesh != input_mesh) { - geometry_set.replace_mesh(output_mesh); - } - - const AttributeDomain result_face_domain = ATTR_DOMAIN_FACE; - - const std::string shell_faces_attribute_name = params.get_input<std::string>("Fill Faces"); - const std::string rim_faces_attribute_name = params.get_input<std::string>("Rim Faces"); - - if (solidify_node_data.flag & MOD_SOLIDIFY_SHELL) { - if (!shell_faces_attribute_name.empty()) { - OutputAttribute_Typed<bool> shell_faces_attribute = - mesh_component.attribute_try_get_for_output_only<bool>(shell_faces_attribute_name, - result_face_domain); - Span<bool> shell_faces_span(shell_faces, shell_faces_attribute->size()); - shell_faces_attribute->set_all(shell_faces_span); - shell_faces_attribute.save(); + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>(); + Mesh *input_mesh = component.get_for_write(); + + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT}; + + Field<float> thickness_field = params.extract_input<Field<float>>("Thickness"); + FieldEvaluator thickness_evaluator{context, domain_size}; + thickness_evaluator.add(thickness_field); + thickness_evaluator.evaluate(); + Array<float> thickness(domain_size); + thickness_evaluator.get_evaluated<float>(0).materialize(thickness); + + char flag = 0; + + if (add_fill) { + flag |= MOD_SOLIDIFY_SHELL; + } + + if (add_rim) { + flag |= MOD_SOLIDIFY_RIM; } - } - - if (solidify_node_data.flag & MOD_SOLIDIFY_RIM) { - if (!rim_faces_attribute_name.empty()) { - OutputAttribute_Typed<bool> rim_faces_attribute = - mesh_component.attribute_try_get_for_output_only<bool>(rim_faces_attribute_name, - result_face_domain); - Span<bool> rim_faces_span(rim_faces, rim_faces_attribute->size()); - rim_faces_attribute->set_all(rim_faces_span); - rim_faces_attribute.save(); + + SolidifyData solidify_node_data = { + self_object, + 1, + offset, + 0.0f, + offset_clamp, + node_storage.nonmanifold_offset_mode, + node_storage.nonmanifold_boundary_mode, + flag, + 0.01f, + 0.0f, + thickness.begin(), + }; + + bool *shell_verts = nullptr; + bool *rim_verts = nullptr; + bool *shell_faces = nullptr; + bool *rim_faces = nullptr; + + Mesh *output_mesh = solidify_nonmanifold( + &solidify_node_data, input_mesh, &shell_verts, &rim_verts, &shell_faces, &rim_faces); + + if (output_mesh != input_mesh) { + component.replace(output_mesh, GeometryOwnershipType::Editable); + + if (params.output_is_required("Fill Faces")) { + fill_id = StrongAnonymousAttributeID("fill_faces"); + if (add_fill) { + OutputAttribute_Typed<bool> shell_faces_attribute = + component.attribute_try_get_for_output_only<bool>(fill_id.get(), ATTR_DOMAIN_FACE); + Span<bool> shell_faces_span(shell_faces, shell_faces_attribute->size()); + shell_faces_attribute->set_all(shell_faces_span); + shell_faces_attribute.save(); + } + } + + if (params.output_is_required("Rim Faces")) { + rim_id = StrongAnonymousAttributeID("rim_faces"); + if (add_rim) { + OutputAttribute_Typed<bool> rim_faces_attribute = + component.attribute_try_get_for_output_only<bool>(rim_id.get(), ATTR_DOMAIN_FACE); + Span<bool> rim_faces_span(rim_faces, rim_faces_attribute->size()); + rim_faces_attribute->set_all(rim_faces_span); + rim_faces_attribute.save(); + } + } } - } - MEM_freeN(shell_verts); - MEM_freeN(rim_verts); - MEM_freeN(shell_faces); - MEM_freeN(rim_faces); + MEM_freeN(shell_verts); + MEM_freeN(rim_verts); + MEM_freeN(shell_faces); + MEM_freeN(rim_faces); + }); + } + if (fill_id) { + params.set_output("Fill Faces", + AnonymousAttributeFieldInput::Create<bool>( + std::move(fill_id), params.attribute_producer_name())); + } + if (rim_id) { + params.set_output("Rim Faces", + AnonymousAttributeFieldInput::Create<bool>( + std::move(rim_id), params.attribute_producer_name())); } - params.set_output("Geometry", geometry_set); + + params.set_output("Mesh", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_solidify void register_node_type_geo_solidify() { + namespace file_ns = blender::nodes::node_geo_solidify; + static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SOLIDIFY, "Solidify", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates(&ntype, geo_node_solidify_in, geo_node_solidify_out); + + geo_node_type_base(&ntype, GEO_NODE_SOLIDIFY, "Solidify", NODE_CLASS_GEOMETRY); + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometrySolidify", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_solidify_init); + node_type_init(&ntype, file_ns::geo_node_solidify_init); node_type_size(&ntype, 172, 100, 600); - node_type_update(&ntype, blender::nodes::geo_node_solidify_update); - ntype.geometry_node_execute = blender::nodes::geo_node_solidify_exec; - ntype.draw_buttons = blender::nodes::geo_node_solidify_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } |