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
This commit is contained in:
		@@ -766,6 +766,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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user