diff options
author | Hans Goudey <h.goudey@me.com> | 2021-03-13 22:13:16 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-03-13 22:13:16 +0300 |
commit | ba3a0dc9ba91e2f55e3632a69f8671079d871a94 (patch) | |
tree | 407aab052755863fdc32d400790a941e50868093 | |
parent | 2966871a7a891bf36b261419a5b09ecff93504e0 (diff) |
Geometry Nodes: Add "normal" attribute for face normals
This commit adds a `normal` attribute on the polygon domain. Since
normal data is derived data purely based off of the location of each
face's vertices, it is exposed as a read-only attribute. After
rB80f7f1070f17, this attribute can be interpolated to the other domains.
Since this attribute is a special case compared to the others, the
implementation subclasses `BuiltinAttributeProvider`. It's possible
there is a better way to abstract this. Something else might also
become apparent if we add similar read-only attributes.
See rB2966871a7a891bf36 for why this is preferred over the previous
implementation.
Differential Revision: https://developer.blender.org/D10677
3 files changed, 64 insertions, 3 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index b25f5286cab..c6e32c3e8bd 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -767,6 +767,65 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { }; /** + * This provider makes face normals available as a read-only float3 attribute. + */ +class NormalAttributeProvider final : public BuiltinAttributeProvider { + public: + NormalAttributeProvider() + : BuiltinAttributeProvider( + "normal", ATTR_DOMAIN_POLYGON, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component) const + { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + /* Use existing normals if possible. */ + if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) && + CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { + const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + + return std::make_unique<ArrayReadAttribute<float3>>( + ATTR_DOMAIN_POLYGON, Span<float3>((const float3 *)data, mesh->totpoly)); + } + + Array<float3> normals(mesh->totpoly); + for (const int i : IndexRange(mesh->totpoly)) { + const MPoly *poly = &mesh->mpoly[i]; + BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); + } + + return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_POLYGON, + std::move(normals)); + } + + WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const + { + return {}; + } + + bool try_delete(GeometryComponent &UNUSED(component)) const + { + return false; + } + + bool try_create(GeometryComponent &UNUSED(component)) const + { + return false; + } + + bool exists(const GeometryComponent &component) const + { + return component.attribute_domain_size(ATTR_DOMAIN_POLYGON) != 0; + } +}; + +/** * In this function all the attribute providers for a mesh component are created. Most data in this * function is statically allocated, because it does not change over time. */ @@ -818,6 +877,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() make_vertex_position_write_attribute, tag_normals_dirty_when_writing_position); + static NormalAttributeProvider normal; + static BuiltinCustomDataLayerProvider material_index("material_index", ATTR_DOMAIN_POLYGON, CD_PROP_INT32, @@ -862,7 +923,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - return ComponentAttributeProviders({&position, &material_index, &shade_smooth}, + return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal}, {&uvs, &vertex_colors, &corner_custom_data, diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 70b48a253ed..fc9d793c119 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -381,7 +381,7 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups, gather_attribute_info(attributes, component_types, set_groups, - {"position", "material_index", "vertex_normal", "shade_smooth"}); + {"position", "material_index", "normal", "shade_smooth"}); join_attributes( set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 45aaf81d63f..54b0c07a0a0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -224,7 +224,7 @@ static void join_components(Span<const MeshComponent *> src_components, Geometry /* Don't copy attributes that are stored directly in the mesh data structs. */ join_attributes(to_base_components(src_components), dst_component, - {"position", "material_index", "vertex_normal", "shade_smooth"}); + {"position", "material_index", "normal", "shade_smooth"}); } static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result) |