Files
test2/source/blender/blenkernel/intern/geometry_component_mesh.cc
Hans Goudey b36eb69038 Geometry Nodes: Output proper face corner normals
Previously, when evaluated on the face corner domain, the normal input
node just returned the face normals, as if the mesh was completely flat
shaded. This ignores face and edge smoothness, and custom face corner
normals. In the past couple years the expected behavior of accessing
normals has become much clearer and this behavior is clearly a mistake
in retrospect.

This commit exposes the same face corner normals used everywhere else
in Blender when the node is evaluated on the corner domain. The old
behavior is accessible with a node property in the sidebar. There is
versioning so old files have the property set and get the same results.

This is split from !132583.

Pull Request: https://projects.blender.org/blender/blender/pulls/133340
2025-01-20 23:57:32 +01:00

187 lines
4.6 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_vector.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.hh"
#include "BKE_mesh.hh"
#include "attribute_access_intern.hh"
namespace blender::bke {
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
* \{ */
MeshComponent::MeshComponent() : GeometryComponent(Type::Mesh) {}
MeshComponent::MeshComponent(Mesh *mesh, GeometryOwnershipType ownership)
: GeometryComponent(Type::Mesh), mesh_(mesh), ownership_(ownership)
{
}
MeshComponent::~MeshComponent()
{
this->clear();
}
GeometryComponentPtr MeshComponent::copy() const
{
MeshComponent *new_component = new MeshComponent();
if (mesh_ != nullptr) {
new_component->mesh_ = BKE_mesh_copy_for_eval(*mesh_);
new_component->ownership_ = GeometryOwnershipType::Owned;
}
return GeometryComponentPtr(new_component);
}
void MeshComponent::clear()
{
BLI_assert(this->is_mutable() || this->is_expired());
if (mesh_ != nullptr) {
if (ownership_ == GeometryOwnershipType::Owned) {
BKE_id_free(nullptr, mesh_);
}
mesh_ = nullptr;
}
}
bool MeshComponent::has_mesh() const
{
return mesh_ != nullptr;
}
void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
this->clear();
mesh_ = mesh;
ownership_ = ownership;
}
Mesh *MeshComponent::release()
{
BLI_assert(this->is_mutable());
Mesh *mesh = mesh_;
mesh_ = nullptr;
return mesh;
}
const Mesh *MeshComponent::get() const
{
return mesh_;
}
Mesh *MeshComponent::get_for_write()
{
BLI_assert(this->is_mutable());
if (ownership_ == GeometryOwnershipType::ReadOnly) {
mesh_ = BKE_mesh_copy_for_eval(*mesh_);
ownership_ = GeometryOwnershipType::Owned;
}
return mesh_;
}
bool MeshComponent::is_empty() const
{
return mesh_ == nullptr;
}
bool MeshComponent::owns_direct_data() const
{
return ownership_ == GeometryOwnershipType::Owned;
}
void MeshComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
if (ownership_ != GeometryOwnershipType::Owned) {
if (mesh_) {
mesh_ = BKE_mesh_copy_for_eval(*mesh_);
}
ownership_ = GeometryOwnershipType::Owned;
}
}
void MeshComponent::count_memory(MemoryCounter &memory) const
{
if (mesh_) {
mesh_->count_memory(memory);
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Normals Field Input
* \{ */
VArray<float3> mesh_normals_varray(const Mesh &mesh,
const IndexMask &mask,
const AttrDomain domain,
const bool no_corner_normals)
{
switch (domain) {
case AttrDomain::Face: {
return VArray<float3>::ForSpan(mesh.face_normals());
}
case AttrDomain::Point: {
return VArray<float3>::ForSpan(mesh.vert_normals());
}
case AttrDomain::Edge: {
/* In this case, start with vertex normals and convert to the edge domain, since the
* conversion from edges to vertices is very simple. Use "manual" domain interpolation
* instead of the GeometryComponent API to avoid calculating unnecessary values and to
* allow normalizing the result more simply. */
Span<float3> vert_normals = mesh.vert_normals();
const Span<int2> edges = mesh.edges();
Array<float3> edge_normals(mask.min_array_size());
mask.foreach_index([&](const int i) {
const int2 &edge = edges[i];
edge_normals[i] = math::normalize(
math::interpolate(vert_normals[edge[0]], vert_normals[edge[1]], 0.5f));
});
return VArray<float3>::ForContainer(std::move(edge_normals));
}
case AttrDomain::Corner: {
if (no_corner_normals) {
return mesh.attributes().adapt_domain(
VArray<float3>::ForSpan(mesh.face_normals()), AttrDomain::Face, AttrDomain::Corner);
}
return VArray<float3>::ForSpan(mesh.corner_normals());
}
default:
return {};
}
}
/** \} */
} // namespace blender::bke
namespace blender::bke {
/* -------------------------------------------------------------------- */
/** \name Attribute Access
* \{ */
std::optional<AttributeAccessor> MeshComponent::attributes() const
{
return AttributeAccessor(mesh_, mesh_attribute_accessor_functions());
}
std::optional<MutableAttributeAccessor> MeshComponent::attributes_for_write()
{
Mesh *mesh = this->get_for_write();
return MutableAttributeAccessor(mesh, mesh_attribute_accessor_functions());
}
/** \} */
} // namespace blender::bke