Geometry Nodes: Use separate field context for each geometry type
Using the same `GeometryComponentFieldContext` for all situations, even when only one geometry type is supported is misleading, and mixes too many different abstraction levels into code that could be simpler. With the attribute API moved out of geometry components recently, the "component" system is just getting in the way here. This commit adds specific field contexts for geometry types: meshes, curves, point clouds, and instances. There are also separate field input helper classes, to help reduce boilerplate for fields that only support specific geometry types. Another benefit of this change is that it separates geometry components from fields, which makes it easier to see the purpose of the two concepts, and how they relate. Because we want to be able to evaluate a field on just `CurvesGeometry` rather than the full `Curves` data-block, the generic "geometry context" had to be changed to avoid using `GeometryComponent`, since there is no corresponding geometry component type. The resulting void pointer is ugly, but only turns up in three places in practice. When Apple clang supports `std::variant`, that could be used instead. Differential Revision: https://developer.blender.org/D15519
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_generic_span.hh"
|
||||
|
@@ -12,22 +12,24 @@
|
||||
|
||||
#include "FN_field.hh"
|
||||
|
||||
struct Mesh;
|
||||
struct PointCloud;
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
class GeometryComponentFieldContext : public fn::FieldContext {
|
||||
struct CurvesGeometry;
|
||||
class GeometryFieldInput;
|
||||
|
||||
class MeshFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const GeometryComponent &component_;
|
||||
const Mesh &mesh_;
|
||||
const eAttrDomain domain_;
|
||||
|
||||
public:
|
||||
GeometryComponentFieldContext(const GeometryComponent &component, const eAttrDomain domain)
|
||||
: component_(component), domain_(domain)
|
||||
MeshFieldContext(const Mesh &mesh, const eAttrDomain domain);
|
||||
const Mesh &mesh() const
|
||||
{
|
||||
}
|
||||
|
||||
const GeometryComponent &geometry_component() const
|
||||
{
|
||||
return component_;
|
||||
return mesh_;
|
||||
}
|
||||
|
||||
eAttrDomain domain() const
|
||||
@@ -36,19 +38,155 @@ class GeometryComponentFieldContext : public fn::FieldContext {
|
||||
}
|
||||
};
|
||||
|
||||
class CurvesFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const CurvesGeometry &curves_;
|
||||
const eAttrDomain domain_;
|
||||
|
||||
public:
|
||||
CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain);
|
||||
|
||||
const CurvesGeometry &curves() const
|
||||
{
|
||||
return curves_;
|
||||
}
|
||||
|
||||
eAttrDomain domain() const
|
||||
{
|
||||
return domain_;
|
||||
}
|
||||
};
|
||||
|
||||
class PointCloudFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const PointCloud &pointcloud_;
|
||||
|
||||
public:
|
||||
PointCloudFieldContext(const PointCloud &pointcloud) : pointcloud_(pointcloud)
|
||||
{
|
||||
}
|
||||
|
||||
const PointCloud &pointcloud() const
|
||||
{
|
||||
return pointcloud_;
|
||||
}
|
||||
};
|
||||
|
||||
class InstancesFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const InstancesComponent &instances_;
|
||||
|
||||
public:
|
||||
InstancesFieldContext(const InstancesComponent &instances) : instances_(instances)
|
||||
{
|
||||
}
|
||||
|
||||
const InstancesComponent &instances() const
|
||||
{
|
||||
return instances_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A field context that can represent meshes, curves, point clouds, or instances,
|
||||
* used for field inputs that can work for multiple geometry types.
|
||||
*/
|
||||
class GeometryFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
/**
|
||||
* Store the geometry as a void pointer instead of a #GeometryComponent to allow referencing data
|
||||
* that doesn't correspond directly to a geometry component type, in this case #CurvesGeometry
|
||||
* instead of #Curves.
|
||||
*/
|
||||
const void *geometry_;
|
||||
const GeometryComponentType type_;
|
||||
const eAttrDomain domain_;
|
||||
|
||||
friend GeometryFieldInput;
|
||||
|
||||
public:
|
||||
GeometryFieldContext(const GeometryComponent &component, eAttrDomain domain);
|
||||
GeometryFieldContext(const void *geometry, GeometryComponentType type, eAttrDomain domain);
|
||||
|
||||
const void *geometry() const
|
||||
{
|
||||
return geometry_;
|
||||
}
|
||||
|
||||
GeometryComponentType type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
eAttrDomain domain() const
|
||||
{
|
||||
return domain_;
|
||||
}
|
||||
|
||||
std::optional<AttributeAccessor> attributes() const;
|
||||
const Mesh *mesh() const;
|
||||
const CurvesGeometry *curves() const;
|
||||
const PointCloud *pointcloud() const;
|
||||
const InstancesComponent *instances() const;
|
||||
|
||||
private:
|
||||
GeometryFieldContext(const Mesh &mesh, eAttrDomain domain);
|
||||
GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain);
|
||||
GeometryFieldContext(const PointCloud &points);
|
||||
GeometryFieldContext(const InstancesComponent &instances);
|
||||
};
|
||||
|
||||
class GeometryFieldInput : public fn::FieldInput {
|
||||
public:
|
||||
using fn::FieldInput::FieldInput;
|
||||
|
||||
GVArray get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope &scope) const override;
|
||||
virtual GVArray get_varray_for_context(const GeometryFieldContext &context,
|
||||
IndexMask mask) const = 0;
|
||||
};
|
||||
|
||||
virtual GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
class MeshFieldInput : public fn::FieldInput {
|
||||
public:
|
||||
using fn::FieldInput::FieldInput;
|
||||
GVArray get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope &scope) const override;
|
||||
virtual GVArray get_varray_for_context(const Mesh &mesh,
|
||||
eAttrDomain domain,
|
||||
IndexMask mask) const = 0;
|
||||
};
|
||||
|
||||
class CurvesFieldInput : public fn::FieldInput {
|
||||
public:
|
||||
using fn::FieldInput::FieldInput;
|
||||
GVArray get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope &scope) const override;
|
||||
virtual GVArray get_varray_for_context(const CurvesGeometry &curves,
|
||||
eAttrDomain domain,
|
||||
IndexMask mask) const = 0;
|
||||
};
|
||||
|
||||
class PointCloudFieldInput : public fn::FieldInput {
|
||||
public:
|
||||
using fn::FieldInput::FieldInput;
|
||||
GVArray get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope &scope) const override;
|
||||
virtual GVArray get_varray_for_context(const PointCloud &pointcloud, IndexMask mask) const = 0;
|
||||
};
|
||||
|
||||
class InstancesFieldInput : public fn::FieldInput {
|
||||
public:
|
||||
using fn::FieldInput::FieldInput;
|
||||
GVArray get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope &scope) const override;
|
||||
virtual GVArray get_varray_for_context(const InstancesComponent &instances,
|
||||
IndexMask mask) const = 0;
|
||||
};
|
||||
|
||||
class AttributeFieldInput : public GeometryFieldInput {
|
||||
private:
|
||||
std::string name_;
|
||||
@@ -72,8 +210,7 @@ class AttributeFieldInput : public GeometryFieldInput {
|
||||
return name_;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
eAttrDomain domain,
|
||||
GVArray get_varray_for_context(const GeometryFieldContext &context,
|
||||
IndexMask mask) const override;
|
||||
|
||||
std::string socket_inspection_name() const override;
|
||||
@@ -89,8 +226,7 @@ class IDAttributeFieldInput : public GeometryFieldInput {
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
eAttrDomain domain,
|
||||
GVArray get_varray_for_context(const GeometryFieldContext &context,
|
||||
IndexMask mask) const override;
|
||||
|
||||
std::string socket_inspection_name() const override;
|
||||
@@ -99,12 +235,9 @@ class IDAttributeFieldInput : public GeometryFieldInput {
|
||||
bool is_equal_to(const fn::FieldNode &other) const override;
|
||||
};
|
||||
|
||||
VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain);
|
||||
VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain);
|
||||
|
||||
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
|
||||
const Mesh &mesh,
|
||||
const IndexMask mask,
|
||||
eAttrDomain domain);
|
||||
VArray<float3> mesh_normals_varray(const Mesh &mesh, const IndexMask mask, eAttrDomain domain);
|
||||
|
||||
class NormalFieldInput : public GeometryFieldInput {
|
||||
public:
|
||||
@@ -113,8 +246,7 @@ class NormalFieldInput : public GeometryFieldInput {
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
GVArray get_varray_for_context(const GeometryFieldContext &context,
|
||||
IndexMask mask) const override;
|
||||
|
||||
std::string socket_inspection_name() const override;
|
||||
@@ -152,8 +284,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
|
||||
return fn::Field<T>{field_input};
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
eAttrDomain domain,
|
||||
GVArray get_varray_for_context(const GeometryFieldContext &context,
|
||||
IndexMask mask) const override;
|
||||
|
||||
std::string socket_inspection_name() const override;
|
||||
@@ -162,10 +293,10 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
|
||||
bool is_equal_to(const fn::FieldNode &other) const override;
|
||||
};
|
||||
|
||||
class CurveLengthFieldInput final : public GeometryFieldInput {
|
||||
class CurveLengthFieldInput final : public CurvesFieldInput {
|
||||
public:
|
||||
CurveLengthFieldInput();
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const CurvesGeometry &curves,
|
||||
eAttrDomain domain,
|
||||
IndexMask mask) const final;
|
||||
uint64_t hash() const override;
|
||||
|
@@ -143,6 +143,7 @@ set(SRC
|
||||
intern/geometry_component_mesh.cc
|
||||
intern/geometry_component_pointcloud.cc
|
||||
intern/geometry_component_volume.cc
|
||||
intern/geometry_fields.cc
|
||||
intern/geometry_set.cc
|
||||
intern/geometry_set_instances.cc
|
||||
intern/gpencil.c
|
||||
|
@@ -5,7 +5,6 @@
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_geometry_fields.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
@@ -794,7 +793,7 @@ void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order)
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component
|
||||
/** \name Attribute API
|
||||
* \{ */
|
||||
|
||||
static blender::GVArray try_adapt_data_type(blender::GVArray varray,
|
||||
@@ -805,123 +804,6 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray,
|
||||
return conversions.try_convert(std::move(varray), to_type);
|
||||
}
|
||||
|
||||
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope &UNUSED(scope)) const
|
||||
{
|
||||
if (const GeometryComponentFieldContext *geometry_context =
|
||||
dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
|
||||
const GeometryComponent &component = geometry_context->geometry_component();
|
||||
const eAttrDomain domain = geometry_context->domain();
|
||||
return this->get_varray_for_context(component, domain, mask);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const
|
||||
{
|
||||
const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
|
||||
if (auto attributes = component.attributes()) {
|
||||
return attributes->lookup(name_, domain, data_type);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string AttributeFieldInput::socket_inspection_name() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
uint64_t AttributeFieldInput::hash() const
|
||||
{
|
||||
return get_default_hash_2(name_, type_);
|
||||
}
|
||||
|
||||
bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) {
|
||||
return name_ == other_typed->name_ && type_ == other_typed->type_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static StringRef get_random_id_attribute_name(const eAttrDomain domain)
|
||||
{
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
case ATTR_DOMAIN_INSTANCE:
|
||||
return "id";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const
|
||||
{
|
||||
|
||||
const StringRef name = get_random_id_attribute_name(domain);
|
||||
if (auto attributes = component.attributes()) {
|
||||
if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the index as the fallback if no random ID attribute exists. */
|
||||
return fn::IndexFieldInput::get_index_varray(mask);
|
||||
}
|
||||
|
||||
std::string IDAttributeFieldInput::socket_inspection_name() const
|
||||
{
|
||||
return TIP_("ID / Index");
|
||||
}
|
||||
|
||||
uint64_t IDAttributeFieldInput::hash() const
|
||||
{
|
||||
/* All random ID attribute inputs are the same within the same evaluation context. */
|
||||
return 92386459827;
|
||||
}
|
||||
|
||||
bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
/* All random ID attribute inputs are the same within the same evaluation context. */
|
||||
return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
|
||||
}
|
||||
|
||||
GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const
|
||||
{
|
||||
const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
|
||||
return component.attributes()->lookup(anonymous_id_.get(), domain, data_type);
|
||||
}
|
||||
|
||||
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
uint64_t AnonymousAttributeFieldInput::hash() const
|
||||
{
|
||||
return get_default_hash_2(anonymous_id_.get(), type_);
|
||||
}
|
||||
|
||||
bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
if (const AnonymousAttributeFieldInput *other_typed =
|
||||
dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) {
|
||||
return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id,
|
||||
const std::optional<eAttrDomain> domain,
|
||||
const std::optional<eCustomDataType> data_type) const
|
||||
|
@@ -206,18 +206,11 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves
|
||||
return results;
|
||||
}
|
||||
|
||||
VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain)
|
||||
VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain)
|
||||
{
|
||||
if (!component.has_curves()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Curves &curves_id = *component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
const VArray<int8_t> types = curves.curve_types();
|
||||
if (curves.is_single_type(CURVE_TYPE_POLY)) {
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return curves.adapt_domain<float3>(
|
||||
VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
|
||||
}
|
||||
|
||||
@@ -228,7 +221,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr
|
||||
}
|
||||
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return curves.adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
|
||||
}
|
||||
|
||||
@@ -241,15 +234,9 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr
|
||||
/** \name Curve Length Field Input
|
||||
* \{ */
|
||||
|
||||
static VArray<float> construct_curve_length_gvarray(const CurveComponent &component,
|
||||
static VArray<float> construct_curve_length_gvarray(const CurvesGeometry &curves,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
if (!component.has_curves()) {
|
||||
return {};
|
||||
}
|
||||
const Curves &curves_id = *component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
curves.ensure_evaluated_lengths();
|
||||
|
||||
VArray<bool> cyclic = curves.cyclic();
|
||||
@@ -263,28 +250,23 @@ static VArray<float> construct_curve_length_gvarray(const CurveComponent &compon
|
||||
}
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
return component.attributes()->adapt_domain<float>(
|
||||
std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
|
||||
return curves.adapt_domain<float>(std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
CurveLengthFieldInput::CurveLengthFieldInput()
|
||||
: GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
|
||||
: CurvesFieldInput(CPPType::get<float>(), "Spline Length node")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray CurveLengthFieldInput::get_varray_for_context(const CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
return construct_curve_length_gvarray(curve_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_curve_length_gvarray(curves, domain);
|
||||
}
|
||||
|
||||
uint64_t CurveLengthFieldInput::hash() const
|
||||
|
@@ -115,8 +115,7 @@ void MeshComponent::ensure_owns_direct_data()
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
|
||||
const Mesh &mesh,
|
||||
VArray<float3> mesh_normals_varray(const Mesh &mesh,
|
||||
const IndexMask mask,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
@@ -150,7 +149,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
|
||||
* 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_component.attributes()->adapt_domain(
|
||||
return mesh_attributes(mesh).adapt_domain(
|
||||
VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
|
||||
ATTR_DOMAIN_FACE,
|
||||
ATTR_DOMAIN_CORNER);
|
||||
|
365
source/blender/blenkernel/intern/geometry_fields.cc
Normal file
365
source/blender/blenkernel/intern/geometry_fields.cc
Normal file
@@ -0,0 +1,365 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_fields.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_type_conversions.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
MeshFieldContext::MeshFieldContext(const Mesh &mesh, const eAttrDomain domain)
|
||||
: mesh_(mesh), domain_(domain)
|
||||
{
|
||||
BLI_assert(mesh_attributes(mesh).domain_supported(domain_));
|
||||
}
|
||||
|
||||
CurvesFieldContext::CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain)
|
||||
: curves_(curves), domain_(domain)
|
||||
{
|
||||
BLI_assert(curves.attributes().domain_supported(domain));
|
||||
}
|
||||
|
||||
GeometryFieldContext::GeometryFieldContext(const void *geometry,
|
||||
const GeometryComponentType type,
|
||||
const eAttrDomain domain)
|
||||
: geometry_(geometry), type_(type), domain_(domain)
|
||||
{
|
||||
BLI_assert(ELEM(type,
|
||||
GEO_COMPONENT_TYPE_MESH,
|
||||
GEO_COMPONENT_TYPE_CURVE,
|
||||
GEO_COMPONENT_TYPE_POINT_CLOUD,
|
||||
GEO_COMPONENT_TYPE_INSTANCES));
|
||||
}
|
||||
|
||||
GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component,
|
||||
const eAttrDomain domain)
|
||||
: type_(component.type()), domain_(domain)
|
||||
{
|
||||
switch (component.type()) {
|
||||
case GEO_COMPONENT_TYPE_MESH: {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
geometry_ = mesh_component.get_for_read();
|
||||
break;
|
||||
}
|
||||
case GEO_COMPONENT_TYPE_CURVE: {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
const Curves *curves = curve_component.get_for_read();
|
||||
geometry_ = curves ? &CurvesGeometry::wrap(curves->geometry) : nullptr;
|
||||
break;
|
||||
}
|
||||
case GEO_COMPONENT_TYPE_POINT_CLOUD: {
|
||||
const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
|
||||
component);
|
||||
geometry_ = pointcloud_component.get_for_read();
|
||||
break;
|
||||
}
|
||||
case GEO_COMPONENT_TYPE_INSTANCES: {
|
||||
const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
|
||||
component);
|
||||
geometry_ = &instances_component;
|
||||
break;
|
||||
}
|
||||
case GEO_COMPONENT_TYPE_VOLUME:
|
||||
case GEO_COMPONENT_TYPE_EDIT:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GeometryFieldContext::GeometryFieldContext(const Mesh &mesh, eAttrDomain domain)
|
||||
: geometry_(&mesh), type_(GEO_COMPONENT_TYPE_MESH), domain_(domain)
|
||||
{
|
||||
}
|
||||
GeometryFieldContext::GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain)
|
||||
: geometry_(&curves), type_(GEO_COMPONENT_TYPE_CURVE), domain_(domain)
|
||||
{
|
||||
}
|
||||
GeometryFieldContext::GeometryFieldContext(const PointCloud &points)
|
||||
: geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT)
|
||||
{
|
||||
}
|
||||
GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances)
|
||||
: geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<AttributeAccessor> GeometryFieldContext::attributes() const
|
||||
{
|
||||
if (const Mesh *mesh = this->mesh()) {
|
||||
return mesh_attributes(*mesh);
|
||||
}
|
||||
if (const CurvesGeometry *curves = this->curves()) {
|
||||
return curves->attributes();
|
||||
}
|
||||
if (const PointCloud *pointcloud = this->pointcloud()) {
|
||||
return pointcloud_attributes(*pointcloud);
|
||||
}
|
||||
if (const InstancesComponent *instances = this->instances()) {
|
||||
return instances->attributes();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
const Mesh *GeometryFieldContext::mesh() const
|
||||
{
|
||||
return this->type() == GEO_COMPONENT_TYPE_MESH ? static_cast<const Mesh *>(geometry_) : nullptr;
|
||||
}
|
||||
const CurvesGeometry *GeometryFieldContext::curves() const
|
||||
{
|
||||
return this->type() == GEO_COMPONENT_TYPE_CURVE ?
|
||||
static_cast<const CurvesGeometry *>(geometry_) :
|
||||
nullptr;
|
||||
}
|
||||
const PointCloud *GeometryFieldContext::pointcloud() const
|
||||
{
|
||||
return this->type() == GEO_COMPONENT_TYPE_POINT_CLOUD ?
|
||||
static_cast<const PointCloud *>(geometry_) :
|
||||
nullptr;
|
||||
}
|
||||
const InstancesComponent *GeometryFieldContext::instances() const
|
||||
{
|
||||
return this->type() == GEO_COMPONENT_TYPE_INSTANCES ?
|
||||
static_cast<const InstancesComponent *>(geometry_) :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
|
||||
const IndexMask mask,
|
||||
ResourceScope & /*scope*/) const
|
||||
{
|
||||
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context(*geometry_context, mask);
|
||||
}
|
||||
if (const MeshFieldContext *mesh_context = dynamic_cast<const MeshFieldContext *>(&context)) {
|
||||
return this->get_varray_for_context({mesh_context->mesh(), mesh_context->domain()}, mask);
|
||||
}
|
||||
if (const CurvesFieldContext *curve_context = dynamic_cast<const CurvesFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context({curve_context->curves(), curve_context->domain()}, mask);
|
||||
}
|
||||
if (const PointCloudFieldContext *point_context = dynamic_cast<const PointCloudFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context({point_context->pointcloud()}, mask);
|
||||
}
|
||||
if (const InstancesFieldContext *instances_context = dynamic_cast<const InstancesFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context({instances_context->instances()}, mask);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context,
|
||||
const IndexMask mask,
|
||||
ResourceScope & /*scope*/) const
|
||||
{
|
||||
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
|
||||
&context)) {
|
||||
if (const Mesh *mesh = geometry_context->mesh()) {
|
||||
return this->get_varray_for_context(*mesh, geometry_context->domain(), mask);
|
||||
}
|
||||
}
|
||||
if (const MeshFieldContext *mesh_context = dynamic_cast<const MeshFieldContext *>(&context)) {
|
||||
return this->get_varray_for_context(mesh_context->mesh(), mesh_context->domain(), mask);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope & /*scope*/) const
|
||||
{
|
||||
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
|
||||
&context)) {
|
||||
if (const CurvesGeometry *curves = geometry_context->curves()) {
|
||||
return this->get_varray_for_context(*curves, geometry_context->domain(), mask);
|
||||
}
|
||||
}
|
||||
if (const CurvesFieldContext *curves_context = dynamic_cast<const CurvesFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context(curves_context->curves(), curves_context->domain(), mask);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
GVArray PointCloudFieldInput::get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope & /*scope*/) const
|
||||
{
|
||||
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
|
||||
&context)) {
|
||||
if (const PointCloud *pointcloud = geometry_context->pointcloud()) {
|
||||
return this->get_varray_for_context(*pointcloud, mask);
|
||||
}
|
||||
}
|
||||
if (const PointCloudFieldContext *point_context = dynamic_cast<const PointCloudFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context(point_context->pointcloud(), mask);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &context,
|
||||
IndexMask mask,
|
||||
ResourceScope & /*scope*/) const
|
||||
{
|
||||
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
|
||||
&context)) {
|
||||
if (const InstancesComponent *instances = geometry_context->instances()) {
|
||||
return this->get_varray_for_context(*instances, mask);
|
||||
}
|
||||
}
|
||||
if (const InstancesFieldContext *instances_context = dynamic_cast<const InstancesFieldContext *>(
|
||||
&context)) {
|
||||
return this->get_varray_for_context(instances_context->instances(), mask);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
GVArray AttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context,
|
||||
IndexMask UNUSED(mask)) const
|
||||
{
|
||||
const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
|
||||
if (auto attributes = context.attributes()) {
|
||||
return attributes->lookup(name_, context.domain(), data_type);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string AttributeFieldInput::socket_inspection_name() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
uint64_t AttributeFieldInput::hash() const
|
||||
{
|
||||
return get_default_hash_2(name_, type_);
|
||||
}
|
||||
|
||||
bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) {
|
||||
return name_ == other_typed->name_ && type_ == other_typed->type_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static StringRef get_random_id_attribute_name(const eAttrDomain domain)
|
||||
{
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
case ATTR_DOMAIN_INSTANCE:
|
||||
return "id";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context,
|
||||
const IndexMask mask) const
|
||||
{
|
||||
|
||||
const StringRef name = get_random_id_attribute_name(context.domain());
|
||||
if (auto attributes = context.attributes()) {
|
||||
if (GVArray attribute = attributes->lookup(name, context.domain(), CD_PROP_INT32)) {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the index as the fallback if no random ID attribute exists. */
|
||||
return fn::IndexFieldInput::get_index_varray(mask);
|
||||
}
|
||||
|
||||
std::string IDAttributeFieldInput::socket_inspection_name() const
|
||||
{
|
||||
return TIP_("ID / Index");
|
||||
}
|
||||
|
||||
uint64_t IDAttributeFieldInput::hash() const
|
||||
{
|
||||
/* All random ID attribute inputs are the same within the same evaluation context. */
|
||||
return 92386459827;
|
||||
}
|
||||
|
||||
bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
/* All random ID attribute inputs are the same within the same evaluation context. */
|
||||
return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
|
||||
}
|
||||
|
||||
GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context,
|
||||
const IndexMask /*mask*/) const
|
||||
{
|
||||
const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
|
||||
return context.attributes()->lookup(anonymous_id_.get(), context.domain(), data_type);
|
||||
}
|
||||
|
||||
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
uint64_t AnonymousAttributeFieldInput::hash() const
|
||||
{
|
||||
return get_default_hash_2(anonymous_id_.get(), type_);
|
||||
}
|
||||
|
||||
bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
if (const AnonymousAttributeFieldInput *other_typed =
|
||||
dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) {
|
||||
return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh and Curve Normals Field Input
|
||||
* \{ */
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
GVArray NormalFieldInput::get_varray_for_context(const GeometryFieldContext &context,
|
||||
const IndexMask mask) const
|
||||
{
|
||||
if (const Mesh *mesh = context.mesh()) {
|
||||
return mesh_normals_varray(*mesh, mask, context.domain());
|
||||
}
|
||||
if (const CurvesGeometry *curves = context.curves()) {
|
||||
return curve_normals_varray(*curves, context.domain());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string NormalFieldInput::socket_inspection_name() const
|
||||
{
|
||||
return TIP_("Normal");
|
||||
}
|
||||
|
||||
uint64_t NormalFieldInput::hash() const
|
||||
{
|
||||
return 213980475983;
|
||||
}
|
||||
|
||||
bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/** \} */
|
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_fields.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
@@ -633,48 +632,6 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh and Curve Normals Field Input
|
||||
* \{ */
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
if (const Mesh *mesh = mesh_component.get_for_read()) {
|
||||
return mesh_normals_varray(mesh_component, *mesh, mask, domain);
|
||||
}
|
||||
}
|
||||
else if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
return curve_normals_varray(curve_component, domain);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string NormalFieldInput::socket_inspection_name() const
|
||||
{
|
||||
return TIP_("Normal");
|
||||
}
|
||||
|
||||
uint64_t NormalFieldInput::hash() const
|
||||
{
|
||||
return 213980475983;
|
||||
}
|
||||
|
||||
bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
|
||||
{
|
||||
return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name C API
|
||||
* \{ */
|
||||
|
@@ -568,7 +568,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
|
||||
GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
|
||||
GArray<> evaluated_array(field.cpp_type(), domain_num);
|
||||
|
||||
bke::GeometryComponentFieldContext field_context{component, domain};
|
||||
bke::GeometryFieldContext field_context{component, domain};
|
||||
fn::FieldEvaluator field_evaluator{field_context, domain_num};
|
||||
field_evaluator.add_with_destination(field, evaluated_array);
|
||||
field_evaluator.evaluate();
|
||||
|
@@ -4,12 +4,12 @@
|
||||
|
||||
#include "FN_field.hh"
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
|
||||
struct Curves;
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
using bke::CurvesGeometry;
|
||||
|
||||
/**
|
||||
* Create new curves where the selected curves have been resampled with a number of uniform-length
|
||||
* samples defined by the count field. Interpolate attributes to the result, with an accuracy that
|
||||
@@ -17,23 +17,23 @@ namespace blender::geometry {
|
||||
*
|
||||
* \note The values provided by the #count_field are clamped to 1 or greater.
|
||||
*/
|
||||
Curves *resample_to_count(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field);
|
||||
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field);
|
||||
|
||||
/**
|
||||
* Create new curves resampled to make each segment have the length specified by the
|
||||
* #segment_length field input, rounded to make the length of each segment the same.
|
||||
* The accuracy will depend on the curve's resolution parameter.
|
||||
*/
|
||||
Curves *resample_to_length(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<float> &segment_length_field);
|
||||
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<float> &segment_length_field);
|
||||
|
||||
/**
|
||||
* Evaluate each selected curve to its implicit evaluated points.
|
||||
*/
|
||||
Curves *resample_to_evaluated(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field);
|
||||
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field);
|
||||
|
||||
} // namespace blender::geometry
|
||||
|
@@ -88,20 +88,20 @@ static bool interpolate_attribute_to_poly_curve(const bke::AttributeIDRef &attri
|
||||
* Retrieve spans from source and result attributes.
|
||||
*/
|
||||
static void retrieve_attribute_spans(const Span<bke::AttributeIDRef> ids,
|
||||
const CurveComponent &src_component,
|
||||
CurveComponent &dst_component,
|
||||
const CurvesGeometry &src_curves,
|
||||
CurvesGeometry &dst_curves,
|
||||
Vector<GSpan> &src,
|
||||
Vector<GMutableSpan> &dst,
|
||||
Vector<bke::GSpanAttributeWriter> &dst_attributes)
|
||||
{
|
||||
for (const int i : ids.index_range()) {
|
||||
GVArray src_attribute = src_component.attributes()->lookup(ids[i], ATTR_DOMAIN_POINT);
|
||||
GVArray src_attribute = src_curves.attributes().lookup(ids[i], ATTR_DOMAIN_POINT);
|
||||
BLI_assert(src_attribute);
|
||||
src.append(src_attribute.get_internal_span());
|
||||
|
||||
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
|
||||
bke::GSpanAttributeWriter dst_attribute =
|
||||
dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
|
||||
dst_curves.attributes_for_write().lookup_or_add_for_write_only_span(
|
||||
ids[i], ATTR_DOMAIN_POINT, data_type);
|
||||
dst.append(dst_attribute.span);
|
||||
dst_attributes.append(std::move(dst_attribute));
|
||||
@@ -121,16 +121,13 @@ struct AttributesForInterpolation : NonCopyable, NonMovable {
|
||||
/**
|
||||
* Gather a set of all generic attribute IDs to copy to the result curves.
|
||||
*/
|
||||
static void gather_point_attributes_to_interpolate(const CurveComponent &src_component,
|
||||
CurveComponent &dst_component,
|
||||
static void gather_point_attributes_to_interpolate(const CurvesGeometry &src_curves,
|
||||
CurvesGeometry &dst_curves,
|
||||
AttributesForInterpolation &result)
|
||||
{
|
||||
bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(
|
||||
dst_component.get_for_write()->geometry);
|
||||
|
||||
VectorSet<bke::AttributeIDRef> ids;
|
||||
VectorSet<bke::AttributeIDRef> ids_no_interpolation;
|
||||
src_component.attributes()->for_all(
|
||||
src_curves.attributes().for_all(
|
||||
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_POINT) {
|
||||
return true;
|
||||
@@ -152,29 +149,25 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com
|
||||
ids.remove_contained("position");
|
||||
|
||||
retrieve_attribute_spans(
|
||||
ids, src_component, dst_component, result.src, result.dst, result.dst_attributes);
|
||||
ids, src_curves, dst_curves, result.src, result.dst, result.dst_attributes);
|
||||
|
||||
/* Attributes that aren't interpolated like Bezier handles still have to be copied
|
||||
* to the result when there are any unselected curves of the corresponding type. */
|
||||
retrieve_attribute_spans(ids_no_interpolation,
|
||||
src_component,
|
||||
dst_component,
|
||||
src_curves,
|
||||
dst_curves,
|
||||
result.src_no_interpolation,
|
||||
result.dst_no_interpolation,
|
||||
result.dst_attributes);
|
||||
}
|
||||
|
||||
static Curves *resample_to_uniform(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field)
|
||||
static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field)
|
||||
{
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
|
||||
src_component.get_for_read()->geometry);
|
||||
|
||||
/* Create the new curves without any points and evaluate the final count directly
|
||||
* into the offsets array, in order to be accumulated into offsets later. */
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
|
||||
bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
|
||||
CurvesGeometry dst_curves = CurvesGeometry(0, src_curves.curves_num());
|
||||
|
||||
/* Directly copy curve attributes, since they stay the same (except for curve types). */
|
||||
CustomData_copy(&src_curves.curve_data,
|
||||
@@ -184,7 +177,7 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
|
||||
src_curves.curves_num());
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
|
||||
bke::GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(count_field, dst_offsets);
|
||||
@@ -207,9 +200,7 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
|
||||
AttributesForInterpolation attributes;
|
||||
CurveComponent dst_component;
|
||||
dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
|
||||
gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
|
||||
gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes);
|
||||
|
||||
src_curves.ensure_evaluated_lengths();
|
||||
|
||||
@@ -322,32 +313,30 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
return dst_curves_id;
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
Curves *resample_to_count(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field)
|
||||
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field)
|
||||
{
|
||||
return resample_to_uniform(src_component, selection_field, get_count_input_max_one(count_field));
|
||||
return resample_to_uniform(src_curves, selection_field, get_count_input_max_one(count_field));
|
||||
}
|
||||
|
||||
Curves *resample_to_length(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<float> &segment_length_field)
|
||||
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<float> &segment_length_field)
|
||||
{
|
||||
return resample_to_uniform(
|
||||
src_component, selection_field, get_count_input_from_length(segment_length_field));
|
||||
src_curves, selection_field, get_count_input_from_length(segment_length_field));
|
||||
}
|
||||
|
||||
Curves *resample_to_evaluated(const CurveComponent &src_component,
|
||||
const fn::Field<bool> &selection_field)
|
||||
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||
const fn::Field<bool> &selection_field)
|
||||
{
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
|
||||
src_component.get_for_read()->geometry);
|
||||
src_curves.ensure_evaluated_offsets();
|
||||
|
||||
bke::GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
@@ -355,8 +344,7 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
|
||||
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
|
||||
src_curves.curves_range(), nullptr);
|
||||
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
|
||||
bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
|
||||
CurvesGeometry dst_curves(0, src_curves.curves_num());
|
||||
|
||||
/* Directly copy curve attributes, since they stay the same (except for curve types). */
|
||||
CustomData_copy(&src_curves.curve_data,
|
||||
@@ -384,9 +372,7 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
|
||||
AttributesForInterpolation attributes;
|
||||
CurveComponent dst_component;
|
||||
dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
|
||||
gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
|
||||
gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes);
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
|
||||
const IndexMask sliced_selection = selection.slice(selection_range);
|
||||
@@ -445,7 +431,7 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
return dst_curves_id;
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
||||
|
@@ -1002,7 +1002,7 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
|
||||
continue;
|
||||
}
|
||||
const int domain_size = attributes.domain_size(domain);
|
||||
blender::bke::GeometryComponentFieldContext field_context{component, domain};
|
||||
blender::bke::GeometryFieldContext field_context{component, domain};
|
||||
blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
|
||||
for (const OutputAttributeInfo &output_info : outputs_info) {
|
||||
const CPPType &type = output_info.field.cpp_type();
|
||||
|
@@ -28,8 +28,6 @@ using bke::AttributeReader;
|
||||
using bke::AttributeWriter;
|
||||
using bke::GAttributeReader;
|
||||
using bke::GAttributeWriter;
|
||||
using bke::GeometryComponentFieldContext;
|
||||
using bke::GeometryFieldInput;
|
||||
using bke::GSpanAttributeWriter;
|
||||
using bke::MutableAttributeAccessor;
|
||||
using bke::SpanAttributeWriter;
|
||||
|
@@ -192,7 +192,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> class AccumulateFieldInput final : public GeometryFieldInput {
|
||||
template<typename T> class AccumulateFieldInput final : public bke::GeometryFieldInput {
|
||||
private:
|
||||
Field<T> input_;
|
||||
Field<int> group_index_;
|
||||
@@ -204,7 +204,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
|
||||
Field<T> input,
|
||||
Field<int> group_index,
|
||||
AccumulationMode accumulation_mode)
|
||||
: GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
|
||||
: bke::GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
|
||||
input_(input),
|
||||
group_index_(group_index),
|
||||
source_domain_(source_domain),
|
||||
@@ -212,18 +212,18 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
const GeometryComponentFieldContext field_context{component, source_domain_};
|
||||
const int domain_size = component.attribute_domain_size(field_context.domain());
|
||||
const AttributeAccessor attributes = *context.attributes();
|
||||
const int domain_size = attributes.domain_size(source_domain_);
|
||||
if (domain_size == 0) {
|
||||
return {};
|
||||
}
|
||||
const AttributeAccessor attributes = *component.attributes();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
const bke::GeometryFieldContext source_context{
|
||||
context.geometry(), context.type(), source_domain_};
|
||||
fn::FieldEvaluator evaluator{source_context, domain_size};
|
||||
evaluator.add(input_);
|
||||
evaluator.add(group_index_);
|
||||
evaluator.evaluate();
|
||||
@@ -266,7 +266,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
|
||||
}
|
||||
|
||||
return attributes.adapt_domain<T>(
|
||||
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
|
||||
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, context.domain());
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -287,7 +287,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class TotalFieldInput final : public GeometryFieldInput {
|
||||
template<typename T> class TotalFieldInput final : public bke::GeometryFieldInput {
|
||||
private:
|
||||
Field<T> input_;
|
||||
Field<int> group_index_;
|
||||
@@ -295,25 +295,25 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
|
||||
|
||||
public:
|
||||
TotalFieldInput(const eAttrDomain source_domain, Field<T> input, Field<int> group_index)
|
||||
: GeometryFieldInput(CPPType::get<T>(), "Total Value"),
|
||||
: bke::GeometryFieldInput(CPPType::get<T>(), "Total Value"),
|
||||
input_(input),
|
||||
group_index_(group_index),
|
||||
source_domain_(source_domain)
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
|
||||
IndexMask /*mask*/) const final
|
||||
{
|
||||
const GeometryComponentFieldContext field_context{component, source_domain_};
|
||||
const int domain_size = component.attribute_domain_size(field_context.domain());
|
||||
const AttributeAccessor attributes = *context.attributes();
|
||||
const int domain_size = attributes.domain_size(source_domain_);
|
||||
if (domain_size == 0) {
|
||||
return {};
|
||||
}
|
||||
const AttributeAccessor attributes = *component.attributes();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
const bke::GeometryFieldContext source_context{
|
||||
context.geometry(), context.type(), source_domain_};
|
||||
fn::FieldEvaluator evaluator{source_context, domain_size};
|
||||
evaluator.add(input_);
|
||||
evaluator.add(group_index_);
|
||||
evaluator.evaluate();
|
||||
@@ -339,7 +339,7 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
|
||||
return attributes.adapt_domain<T>(
|
||||
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
|
||||
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, context.domain());
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -115,7 +115,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
|
||||
if (domain_size == 0) {
|
||||
return;
|
||||
}
|
||||
GeometryComponentFieldContext field_context{component, domain};
|
||||
bke::GeometryFieldContext field_context{component, domain};
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
const IndexMask mask{IndexMask(domain_size)};
|
||||
|
||||
|
@@ -200,7 +200,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
continue;
|
||||
}
|
||||
if (attributes->domain_supported(domain)) {
|
||||
GeometryComponentFieldContext field_context{*component, domain};
|
||||
bke::GeometryFieldContext field_context{*component, domain};
|
||||
const int domain_num = attributes->domain_size(domain);
|
||||
|
||||
fn::FieldEvaluator data_evaluator{field_context, domain_num};
|
||||
@@ -282,7 +282,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
continue;
|
||||
}
|
||||
if (attributes->domain_supported(domain)) {
|
||||
GeometryComponentFieldContext field_context{*component, domain};
|
||||
bke::GeometryFieldContext field_context{*component, domain};
|
||||
const int domain_num = attributes->domain_size(domain);
|
||||
|
||||
fn::FieldEvaluator data_evaluator{field_context, domain_num};
|
||||
|
@@ -27,39 +27,31 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
N_("The selection from the start and end of the splines based on the input sizes"));
|
||||
}
|
||||
|
||||
class EndpointFieldInput final : public GeometryFieldInput {
|
||||
class EndpointFieldInput final : public bke::CurvesFieldInput {
|
||||
Field<int> start_size_;
|
||||
Field<int> end_size_;
|
||||
|
||||
public:
|
||||
EndpointFieldInput(Field<int> start_size, Field<int> end_size)
|
||||
: GeometryFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
|
||||
: bke::CurvesFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
|
||||
start_size_(start_size),
|
||||
end_size_(end_size)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
|
||||
return nullptr;
|
||||
if (domain != ATTR_DOMAIN_POINT) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
if (!curve_component.has_curves()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Curves &curves_id = *curve_component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
if (curves.points_num() == 0) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
|
||||
bke::CurvesFieldContext size_context{curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{size_context, curves.curves_num()};
|
||||
evaluator.add(start_size_);
|
||||
evaluator.add(end_size_);
|
||||
|
@@ -72,10 +72,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const Curves &curves_id = *component.get_for_read();
|
||||
const Curves &curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
|
||||
bke::CurvesFieldContext context{curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{context, curves.points_num()};
|
||||
evaluator.add(radius_field);
|
||||
|
||||
|
@@ -70,35 +70,28 @@ static void select_by_handle_type(const bke::CurvesGeometry &curves,
|
||||
}
|
||||
}
|
||||
|
||||
class HandleTypeFieldInput final : public GeometryFieldInput {
|
||||
class HandleTypeFieldInput final : public bke::CurvesFieldInput {
|
||||
HandleType type_;
|
||||
GeometryNodeCurveHandleMode mode_;
|
||||
|
||||
public:
|
||||
HandleTypeFieldInput(HandleType type, GeometryNodeCurveHandleMode mode)
|
||||
: GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
|
||||
: bke::CurvesFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
|
||||
type_(type),
|
||||
mode_(mode)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
|
||||
if (domain != ATTR_DOMAIN_POINT) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
const Curves *curves_id = curve_component.get_for_read();
|
||||
if (curves_id == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Array<bool> selection(mask.min_array_size());
|
||||
select_by_handle_type(bke::CurvesGeometry::wrap(curves_id->geometry), type_, mode_, selection);
|
||||
select_by_handle_type(curves, type_, mode_, selection);
|
||||
return VArray<bool>::ForContainer(std::move(selection));
|
||||
}
|
||||
|
||||
|
@@ -66,12 +66,14 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
case GEO_NODE_CURVE_RESAMPLE_COUNT: {
|
||||
Field<int> count = params.extract_input<Field<int>>("Count");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
|
||||
if (const Curves *src_curves = component->get_for_read()) {
|
||||
Curves *dst_curves = geometry::resample_to_count(*component, selection, count);
|
||||
bke::curves_copy_parameters(*src_curves, *dst_curves);
|
||||
geometry.replace_curves(dst_curves);
|
||||
}
|
||||
if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
|
||||
src_curves_id->geometry);
|
||||
bke::CurvesGeometry dst_curves = geometry::resample_to_count(
|
||||
src_curves, selection, count);
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
|
||||
bke::curves_copy_parameters(*src_curves_id, *dst_curves_id);
|
||||
geometry.replace_curves(dst_curves_id);
|
||||
}
|
||||
});
|
||||
break;
|
||||
@@ -79,24 +81,27 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
|
||||
Field<float> length = params.extract_input<Field<float>>("Length");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
|
||||
if (const Curves *src_curves = component->get_for_read()) {
|
||||
Curves *dst_curves = geometry::resample_to_length(*component, selection, length);
|
||||
bke::curves_copy_parameters(*src_curves, *dst_curves);
|
||||
geometry.replace_curves(dst_curves);
|
||||
}
|
||||
if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
|
||||
src_curves_id->geometry);
|
||||
bke::CurvesGeometry dst_curves = geometry::resample_to_length(
|
||||
src_curves, selection, length);
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
|
||||
bke::curves_copy_parameters(*src_curves_id, *dst_curves_id);
|
||||
geometry.replace_curves(dst_curves_id);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
|
||||
if (const Curves *src_curves = component->get_for_read()) {
|
||||
Curves *dst_curves = geometry::resample_to_evaluated(*component, selection);
|
||||
bke::curves_copy_parameters(*src_curves, *dst_curves);
|
||||
geometry.replace_curves(dst_curves);
|
||||
}
|
||||
if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
|
||||
src_curves_id->geometry);
|
||||
bke::CurvesGeometry dst_curves = geometry::resample_to_evaluated(src_curves, selection);
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
|
||||
bke::curves_copy_parameters(*src_curves_id, *dst_curves_id);
|
||||
geometry.replace_curves(dst_curves_id);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
@@ -23,14 +23,12 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (!geometry_set.has_curves()) {
|
||||
return;
|
||||
}
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
|
||||
|
||||
Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
|
||||
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
|
||||
|
||||
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
|
||||
selection_evaluator.add(selection_field);
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator selection_evaluator{field_context, src_curves.curves_num()};
|
||||
selection_evaluator.add(params.get_input<Field<bool>>("Selection"));
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
if (selection.is_empty()) {
|
||||
|
@@ -51,15 +51,12 @@ static HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
|
||||
return BEZIER_HANDLE_AUTO;
|
||||
}
|
||||
|
||||
static void set_type_in_component(CurveComponent &component,
|
||||
const GeometryNodeCurveHandleMode mode,
|
||||
const HandleType new_handle_type,
|
||||
const Field<bool> &selection_field)
|
||||
static void set_handle_type(bke::CurvesGeometry &curves,
|
||||
const GeometryNodeCurveHandleMode mode,
|
||||
const HandleType new_handle_type,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
Curves &curves_id = *component.get_for_write();
|
||||
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.points_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
@@ -93,21 +90,17 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
std::atomic<bool> has_bezier = false;
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_curves()) {
|
||||
return;
|
||||
}
|
||||
has_curves = true;
|
||||
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const AttributeAccessor attributes = *component.attributes();
|
||||
if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) {
|
||||
return;
|
||||
}
|
||||
has_bezier = true;
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
|
||||
has_curves = true;
|
||||
const AttributeAccessor attributes = curves.attributes();
|
||||
if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) {
|
||||
return;
|
||||
}
|
||||
has_bezier = true;
|
||||
|
||||
set_type_in_component(geometry_set.get_component_for_write<CurveComponent>(),
|
||||
mode,
|
||||
new_handle_type,
|
||||
selection_field);
|
||||
set_handle_type(curves, mode, new_handle_type, selection_field);
|
||||
}
|
||||
});
|
||||
|
||||
if (has_curves && !has_bezier) {
|
||||
|
@@ -203,26 +203,18 @@ static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &c
|
||||
return {};
|
||||
}
|
||||
|
||||
class CurveParameterFieldInput final : public GeometryFieldInput {
|
||||
class CurveParameterFieldInput final : public bke::CurvesFieldInput {
|
||||
public:
|
||||
CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node")
|
||||
CurveParameterFieldInput() : bke::CurvesFieldInput(CPPType::get<float>(), "Curve Parameter node")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
if (curve_component.has_curves()) {
|
||||
const Curves &curves_id = *curve_component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
return construct_curve_parameter_varray(curves, mask, domain);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return construct_curve_parameter_varray(curves, mask, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -237,26 +229,19 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
class CurveLengthParameterFieldInput final : public GeometryFieldInput {
|
||||
class CurveLengthParameterFieldInput final : public bke::CurvesFieldInput {
|
||||
public:
|
||||
CurveLengthParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
|
||||
CurveLengthParameterFieldInput()
|
||||
: bke::CurvesFieldInput(CPPType::get<float>(), "Curve Length node")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
if (curve_component.has_curves()) {
|
||||
const Curves &curves_id = *curve_component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
return construct_curve_length_parameter_varray(curves, mask, domain);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return construct_curve_length_parameter_varray(curves, mask, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -271,26 +256,18 @@ class CurveLengthParameterFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
class IndexOnSplineFieldInput final : public GeometryFieldInput {
|
||||
class IndexOnSplineFieldInput final : public bke::CurvesFieldInput {
|
||||
public:
|
||||
IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index")
|
||||
IndexOnSplineFieldInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Spline Index")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
if (curve_component.has_curves()) {
|
||||
const Curves &curves_id = *curve_component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
return construct_index_on_spline_varray(curves, mask, domain);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return construct_index_on_spline_varray(curves, mask, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -45,14 +45,13 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (!geometry_set.has_curves()) {
|
||||
return;
|
||||
}
|
||||
const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const Curves &src_curves_id = *src_component.get_for_read();
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
|
||||
if (src_curves.is_single_type(dst_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
|
@@ -34,11 +34,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const Curves &src_curves_id = *component.get_for_read();
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.points_num()};
|
||||
evaluator.add(cuts_field);
|
||||
evaluator.evaluate();
|
||||
|
@@ -504,19 +504,17 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
|
||||
if (!geometry_set.has_curves()) {
|
||||
return;
|
||||
}
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
|
||||
|
||||
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.curves_num()};
|
||||
evaluator.add(start_field);
|
||||
evaluator.add(end_field);
|
||||
evaluator.evaluate();
|
||||
const VArray<float> starts = evaluator.get_evaluated<float>(0);
|
||||
const VArray<float> ends = evaluator.get_evaluated<float>(1);
|
||||
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
std::unique_ptr<CurveEval> curve = curves_to_curve_eval(src_curves_id);
|
||||
MutableSpan<SplinePtr> splines = curve->splines();
|
||||
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_curves.hh"
|
||||
@@ -316,18 +317,19 @@ static void delete_curves_selection(GeometrySet &geometry_set,
|
||||
const Field<bool> &selection_field,
|
||||
const eAttrDomain selection_domain)
|
||||
{
|
||||
const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
GeometryComponentFieldContext field_context{src_component, selection_domain};
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
|
||||
|
||||
const int domain_num = src_component.attribute_domain_size(selection_domain);
|
||||
fn::FieldEvaluator evaluator{field_context, domain_num};
|
||||
const int domain_size = src_curves.attributes().domain_size(selection_domain);
|
||||
bke::CurvesFieldContext field_context{src_curves, selection_domain};
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
|
||||
if (selection.is_empty()) {
|
||||
return;
|
||||
}
|
||||
if (selection.size() == domain_num) {
|
||||
if (selection.size() == domain_size) {
|
||||
geometry_set.remove<CurveComponent>();
|
||||
return;
|
||||
}
|
||||
@@ -347,11 +349,10 @@ static void delete_curves_selection(GeometrySet &geometry_set,
|
||||
static void separate_point_cloud_selection(GeometrySet &geometry_set,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
const PointCloudComponent &src_points =
|
||||
*geometry_set.get_component_for_read<PointCloudComponent>();
|
||||
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
|
||||
const PointCloud &src_pointcloud = *geometry_set.get_pointcloud_for_read();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
|
||||
bke::PointCloudFieldContext field_context{src_pointcloud};
|
||||
fn::FieldEvaluator evaluator{field_context, src_pointcloud.totpoint};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
|
||||
@@ -367,7 +368,7 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
|
||||
{GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
|
||||
|
||||
copy_attributes_based_on_mask(attributes,
|
||||
bke::pointcloud_attributes(*src_points.get_for_read()),
|
||||
bke::pointcloud_attributes(src_pointcloud),
|
||||
bke::pointcloud_attributes_for_write(*pointcloud),
|
||||
ATTR_DOMAIN_POINT,
|
||||
selection);
|
||||
@@ -378,7 +379,7 @@ static void delete_selected_instances(GeometrySet &geometry_set,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
|
||||
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
|
||||
bke::GeometryFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, instances.instances_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -1063,11 +1064,10 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
|
||||
const eAttrDomain selection_domain,
|
||||
const GeometryNodeDeleteGeometryMode mode)
|
||||
{
|
||||
const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
GeometryComponentFieldContext field_context{src_component, selection_domain};
|
||||
|
||||
const Mesh &src_mesh = *geometry_set.get_mesh_for_read();
|
||||
bke::MeshFieldContext field_context{src_mesh, selection_domain};
|
||||
fn::FieldEvaluator evaluator{field_context,
|
||||
src_component.attribute_domain_size(selection_domain)};
|
||||
bke::mesh_attributes(src_mesh).domain_size(selection_domain)};
|
||||
evaluator.add(selection_field);
|
||||
evaluator.evaluate();
|
||||
const VArray<bool> selection = evaluator.get_evaluated<bool>(0);
|
||||
@@ -1078,8 +1078,7 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
|
||||
|
||||
const VArraySpan<bool> selection_span{selection};
|
||||
|
||||
do_mesh_separation(
|
||||
geometry_set, *src_component.get_for_read(), selection_span, selection_domain, mode);
|
||||
do_mesh_separation(geometry_set, src_mesh, selection_span, selection_domain, mode);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_delete_geometry_cc
|
||||
|
@@ -283,15 +283,14 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void propagate_existing_attributes(
|
||||
const MeshComponent &mesh_component,
|
||||
const Mesh &mesh,
|
||||
const Map<AttributeIDRef, AttributeKind> &attributes,
|
||||
GeometryComponent &point_component,
|
||||
PointCloud &points,
|
||||
const Span<float3> bary_coords,
|
||||
const Span<int> looptri_indices)
|
||||
{
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
const AttributeAccessor mesh_attributes = *mesh_component.attributes();
|
||||
MutableAttributeAccessor point_attributes = *point_component.attributes_for_write();
|
||||
const AttributeAccessor mesh_attributes = bke::mesh_attributes(mesh);
|
||||
MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(points);
|
||||
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
@@ -326,30 +325,29 @@ struct AttributeOutputs {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_component,
|
||||
PointCloudComponent &point_component,
|
||||
BLI_NOINLINE static void compute_attribute_outputs(const Mesh &mesh,
|
||||
PointCloud &points,
|
||||
const Span<float3> bary_coords,
|
||||
const Span<int> looptri_indices,
|
||||
const AttributeOutputs &attribute_outputs)
|
||||
{
|
||||
MutableAttributeAccessor pointcloud_attributes = *point_component.attributes_for_write();
|
||||
MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(points);
|
||||
|
||||
SpanAttributeWriter<int> ids = pointcloud_attributes.lookup_or_add_for_write_only_span<int>(
|
||||
SpanAttributeWriter<int> ids = point_attributes.lookup_or_add_for_write_only_span<int>(
|
||||
"id", ATTR_DOMAIN_POINT);
|
||||
|
||||
SpanAttributeWriter<float3> normals;
|
||||
SpanAttributeWriter<float3> rotations;
|
||||
|
||||
if (attribute_outputs.normal_id) {
|
||||
normals = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
|
||||
normals = point_attributes.lookup_or_add_for_write_only_span<float3>(
|
||||
attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT);
|
||||
}
|
||||
if (attribute_outputs.rotation_id) {
|
||||
rotations = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
|
||||
rotations = point_attributes.lookup_or_add_for_write_only_span<float3>(
|
||||
attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
|
||||
BKE_mesh_runtime_looptri_len(&mesh)};
|
||||
|
||||
@@ -389,16 +387,15 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
|
||||
}
|
||||
}
|
||||
|
||||
static Array<float> calc_full_density_factors_with_selection(const MeshComponent &component,
|
||||
static Array<float> calc_full_density_factors_with_selection(const Mesh &mesh,
|
||||
const Field<float> &density_field,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER;
|
||||
GeometryComponentFieldContext field_context{component, attribute_domain};
|
||||
const int domain_size = component.attribute_domain_size(attribute_domain);
|
||||
|
||||
const eAttrDomain domain = ATTR_DOMAIN_CORNER;
|
||||
const int domain_size = bke::mesh_attributes(mesh).domain_size(domain);
|
||||
Array<float> densities(domain_size, 0.0f);
|
||||
|
||||
bke::MeshFieldContext field_context{mesh, domain};
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(density_field, densities.as_mutable_span());
|
||||
@@ -406,7 +403,7 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
|
||||
return densities;
|
||||
}
|
||||
|
||||
static void distribute_points_random(const MeshComponent &component,
|
||||
static void distribute_points_random(const Mesh &mesh,
|
||||
const Field<float> &density_field,
|
||||
const Field<bool> &selection_field,
|
||||
const int seed,
|
||||
@@ -415,12 +412,11 @@ static void distribute_points_random(const MeshComponent &component,
|
||||
Vector<int> &looptri_indices)
|
||||
{
|
||||
const Array<float> densities = calc_full_density_factors_with_selection(
|
||||
component, density_field, selection_field);
|
||||
const Mesh &mesh = *component.get_for_read();
|
||||
mesh, density_field, selection_field);
|
||||
sample_mesh_surface(mesh, 1.0f, densities, seed, positions, bary_coords, looptri_indices);
|
||||
}
|
||||
|
||||
static void distribute_points_poisson_disk(const MeshComponent &mesh_component,
|
||||
static void distribute_points_poisson_disk(const Mesh &mesh,
|
||||
const float minimum_distance,
|
||||
const float max_density,
|
||||
const Field<float> &density_factor_field,
|
||||
@@ -430,14 +426,13 @@ static void distribute_points_poisson_disk(const MeshComponent &mesh_component,
|
||||
Vector<float3> &bary_coords,
|
||||
Vector<int> &looptri_indices)
|
||||
{
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
sample_mesh_surface(mesh, max_density, {}, seed, positions, bary_coords, looptri_indices);
|
||||
|
||||
Array<bool> elimination_mask(positions.size(), false);
|
||||
update_elimination_mask_for_close_points(positions, minimum_distance, elimination_mask);
|
||||
|
||||
const Array<float> density_factors = calc_full_density_factors_with_selection(
|
||||
mesh_component, density_factor_field, selection_field);
|
||||
mesh, density_factor_field, selection_field);
|
||||
|
||||
update_elimination_mask_based_on_density_factors(
|
||||
mesh, density_factors, bary_coords, looptri_indices, elimination_mask.as_mutable_span());
|
||||
@@ -457,7 +452,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
|
||||
return;
|
||||
}
|
||||
|
||||
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
const Mesh &mesh = *geometry_set.get_mesh_for_read();
|
||||
|
||||
Vector<float3> positions;
|
||||
Vector<float3> bary_coords;
|
||||
@@ -466,20 +461,15 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
|
||||
switch (method) {
|
||||
case GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM: {
|
||||
const Field<float> density_field = params.get_input<Field<float>>("Density");
|
||||
distribute_points_random(mesh_component,
|
||||
density_field,
|
||||
selection_field,
|
||||
seed,
|
||||
positions,
|
||||
bary_coords,
|
||||
looptri_indices);
|
||||
distribute_points_random(
|
||||
mesh, density_field, selection_field, seed, positions, bary_coords, looptri_indices);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON: {
|
||||
const float minimum_distance = params.get_input<float>("Distance Min");
|
||||
const float density_max = params.get_input<float>("Density Max");
|
||||
const Field<float> density_factors_field = params.get_input<Field<float>>("Density Factor");
|
||||
distribute_points_poisson_disk(mesh_component,
|
||||
distribute_points_poisson_disk(mesh,
|
||||
minimum_distance,
|
||||
density_max,
|
||||
density_factors_field,
|
||||
@@ -510,9 +500,6 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
|
||||
|
||||
geometry_set.replace_pointcloud(pointcloud);
|
||||
|
||||
PointCloudComponent &point_component =
|
||||
geometry_set.get_component_for_write<PointCloudComponent>();
|
||||
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set.gather_attributes_for_propagation(
|
||||
{GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
|
||||
@@ -520,11 +507,9 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
|
||||
/* Position is set separately. */
|
||||
attributes.remove("position");
|
||||
|
||||
propagate_existing_attributes(
|
||||
mesh_component, attributes, point_component, bary_coords, looptri_indices);
|
||||
propagate_existing_attributes(mesh, attributes, *pointcloud, bary_coords, looptri_indices);
|
||||
|
||||
compute_attribute_outputs(
|
||||
mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
|
||||
compute_attribute_outputs(mesh, *pointcloud, bary_coords, looptri_indices, attribute_outputs);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
@@ -334,11 +334,10 @@ static void duplicate_curves(GeometrySet &geometry_set,
|
||||
geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_CURVE});
|
||||
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
|
||||
|
||||
const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const Curves &curves_id = *src_component.get_for_read();
|
||||
const Curves &curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
|
||||
FieldEvaluator evaluator{field_context, curves.curves_num()};
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -522,14 +521,13 @@ static void duplicate_faces(GeometrySet &geometry_set,
|
||||
}
|
||||
geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_MESH});
|
||||
|
||||
const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
const Mesh &mesh = *src_component.get_for_read();
|
||||
const Mesh &mesh = *geometry_set.get_mesh_for_read();
|
||||
Span<MVert> verts(mesh.mvert, mesh.totvert);
|
||||
Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
|
||||
Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_FACE};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator evaluator(field_context, polys.size());
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -724,12 +722,11 @@ static void duplicate_edges(GeometrySet &geometry_set,
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
return;
|
||||
};
|
||||
const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
const Mesh &mesh = *src_component.get_for_read();
|
||||
const Mesh &mesh = *geometry_set.get_mesh_for_read();
|
||||
Span<MVert> verts(mesh.mvert, mesh.totvert);
|
||||
Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_EDGE};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator evaluator{field_context, edges.size()};
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -805,14 +802,13 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
|
||||
const Field<bool> &selection_field,
|
||||
const IndexAttributes &attribute_outputs)
|
||||
{
|
||||
const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const Curves &src_curves_id = *src_component.get_for_read();
|
||||
const Curves &src_curves_id = *geometry_set.get_curves_for_read();
|
||||
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
|
||||
if (src_curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{field_context, src_curves.points_num()};
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -845,7 +841,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
|
||||
|
||||
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
|
||||
GAttributeReader src_attribute = src_curves.attributes().lookup(attribute_id);
|
||||
if (!src_attribute) {
|
||||
continue;
|
||||
}
|
||||
@@ -909,11 +905,10 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
|
||||
const Field<bool> &selection_field,
|
||||
const IndexAttributes &attribute_outputs)
|
||||
{
|
||||
const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
const Mesh &mesh = *geometry_set.get_mesh_for_read();
|
||||
Span<MVert> src_verts(mesh.mvert, mesh.totvert);
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{field_context, src_verts.size()};
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -961,12 +956,10 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
|
||||
const Field<bool> &selection_field,
|
||||
const IndexAttributes &attribute_outputs)
|
||||
{
|
||||
const PointCloudComponent &src_points =
|
||||
*geometry_set.get_component_for_read<PointCloudComponent>();
|
||||
const int point_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
const PointCloud &src_points = *geometry_set.get_pointcloud_for_read();
|
||||
|
||||
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{field_context, point_num};
|
||||
bke::PointCloudFieldContext field_context{src_points};
|
||||
FieldEvaluator evaluator{field_context, src_points.totpoint};
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
@@ -982,11 +975,12 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
|
||||
ATTR_DOMAIN_POINT,
|
||||
offsets,
|
||||
selection,
|
||||
*src_points.attributes(),
|
||||
bke::pointcloud_attributes(src_points),
|
||||
bke::pointcloud_attributes_for_write(*pointcloud));
|
||||
|
||||
copy_stable_id_point(
|
||||
offsets, *src_points.attributes(), bke::pointcloud_attributes_for_write(*pointcloud));
|
||||
copy_stable_id_point(offsets,
|
||||
bke::pointcloud_attributes(src_points),
|
||||
bke::pointcloud_attributes_for_write(*pointcloud));
|
||||
|
||||
if (attribute_outputs.duplicate_index) {
|
||||
create_duplicate_index_attribute(bke::pointcloud_attributes_for_write(*pointcloud),
|
||||
@@ -1055,7 +1049,7 @@ static void duplicate_instances(GeometrySet &geometry_set,
|
||||
const InstancesComponent &src_instances =
|
||||
*geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
GeometryComponentFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
|
||||
bke::GeometryFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
|
||||
FieldEvaluator evaluator{field_context, src_instances.instances_num()};
|
||||
evaluator.add(count_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
|
@@ -70,14 +70,14 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_mesh()) {
|
||||
const Mesh *mesh = geometry_set.get_mesh_for_read();
|
||||
if (mesh == nullptr) {
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
|
||||
return;
|
||||
}
|
||||
|
||||
const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_POINT)};
|
||||
bke::MeshFieldContext context{*mesh, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{context, mesh->totvert};
|
||||
evaluator.add(params.get_input<Field<int>>("Next Vertex Index"));
|
||||
evaluator.add(params.get_input<Field<bool>>("Start Vertices"));
|
||||
evaluator.evaluate();
|
||||
@@ -89,8 +89,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
const Mesh &mesh = *component.get_for_read();
|
||||
geometry_set.replace_curves(edge_paths_to_curves_convert(mesh, start_verts, next_vert));
|
||||
geometry_set.replace_curves(edge_paths_to_curves_convert(*mesh, start_verts, next_vert));
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
|
||||
});
|
||||
|
||||
|
@@ -54,36 +54,26 @@ static void edge_paths_to_selection(const Mesh &src_mesh,
|
||||
}
|
||||
}
|
||||
|
||||
class PathToEdgeSelectionFieldInput final : public GeometryFieldInput {
|
||||
class PathToEdgeSelectionFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
Field<bool> start_vertices_;
|
||||
Field<int> next_vertex_;
|
||||
|
||||
public:
|
||||
PathToEdgeSelectionFieldInput(Field<bool> start_vertices, Field<int> next_vertex)
|
||||
: GeometryFieldInput(CPPType::get<bool>(), "Edge Selection"),
|
||||
: bke::MeshFieldInput(CPPType::get<bool>(), "Edge Selection"),
|
||||
start_vertices_(start_vertices),
|
||||
next_vertex_(next_vertex)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
[[maybe_unused]] IndexMask mask) const final
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{context, mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT)};
|
||||
bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{context, mesh.totvert};
|
||||
evaluator.add(next_vertex_);
|
||||
evaluator.add(start_vertices_);
|
||||
evaluator.evaluate();
|
||||
@@ -94,12 +84,12 @@ class PathToEdgeSelectionFieldInput final : public GeometryFieldInput {
|
||||
return {};
|
||||
}
|
||||
|
||||
Array<bool> selection(mesh->totedge, false);
|
||||
Array<bool> selection(mesh.totedge, false);
|
||||
MutableSpan<bool> selection_span = selection.as_mutable_span();
|
||||
|
||||
edge_paths_to_selection(*mesh, start_verts, next_vert, selection_span);
|
||||
edge_paths_to_selection(mesh, start_verts, next_vert, selection_span);
|
||||
|
||||
return mesh_component.attributes()->adapt_domain<bool>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<bool>(
|
||||
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_EDGE, domain);
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
|
||||
@@ -51,19 +53,18 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_mesh()) {
|
||||
return;
|
||||
if (const Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
|
||||
bke::MeshFieldContext field_context{*mesh, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator selection_evaluator{field_context, mesh->totedge};
|
||||
selection_evaluator.add(selection_field);
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
Mesh *result = mesh_edge_split(*mesh, selection);
|
||||
|
||||
geometry_set.replace_mesh(result);
|
||||
}
|
||||
|
||||
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
|
||||
const int domain_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
|
||||
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
|
||||
selection_evaluator.add(selection_field);
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
geometry_set.replace_mesh(mesh_edge_split(*mesh_component.get_for_read(), selection));
|
||||
});
|
||||
|
||||
params.set_output("Mesh", std::move(geometry_set));
|
||||
|
@@ -61,15 +61,15 @@ struct AttributeOutputs {
|
||||
StrongAnonymousAttributeID side_id;
|
||||
};
|
||||
|
||||
static void save_selection_as_attribute(MeshComponent &component,
|
||||
static void save_selection_as_attribute(Mesh &mesh,
|
||||
const AnonymousAttributeID *id,
|
||||
const eAttrDomain domain,
|
||||
const IndexMask selection)
|
||||
{
|
||||
BLI_assert(!component.attributes()->contains(id));
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
BLI_assert(!attributes.contains(id));
|
||||
|
||||
SpanAttributeWriter<bool> attribute =
|
||||
component.attributes_for_write()->lookup_or_add_for_write_span<bool>(id, domain);
|
||||
SpanAttributeWriter<bool> attribute = attributes.lookup_or_add_for_write_span<bool>(id, domain);
|
||||
/* Rely on the new attribute being zeroed by default. */
|
||||
BLI_assert(!attribute.span.as_span().contains(true));
|
||||
|
||||
@@ -247,16 +247,15 @@ static Array<Vector<int>> create_vert_to_edge_map(const int vert_size,
|
||||
return vert_to_edge_map;
|
||||
}
|
||||
|
||||
static void extrude_mesh_vertices(MeshComponent &component,
|
||||
static void extrude_mesh_vertices(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float3> &offset_field,
|
||||
const AttributeOutputs &attribute_outputs)
|
||||
{
|
||||
Mesh &mesh = *component.get_for_write();
|
||||
const int orig_vert_size = mesh.totvert;
|
||||
const int orig_edge_size = mesh.totedge;
|
||||
|
||||
GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
|
||||
bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{context, mesh.totvert};
|
||||
evaluator.add(offset_field);
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -279,7 +278,7 @@ static void extrude_mesh_vertices(MeshComponent &component,
|
||||
new_edges[i_selection] = new_loose_edge(selection[i_selection], new_vert_range[i_selection]);
|
||||
}
|
||||
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
|
||||
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
|
||||
@@ -326,11 +325,11 @@ static void extrude_mesh_vertices(MeshComponent &component,
|
||||
|
||||
if (attribute_outputs.top_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
|
||||
mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range);
|
||||
mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range);
|
||||
}
|
||||
|
||||
BKE_mesh_runtime_clear_cache(&mesh);
|
||||
@@ -408,18 +407,17 @@ static VectorSet<int> vert_indices_from_edges(const Mesh &mesh, const Span<T> ed
|
||||
return vert_indices;
|
||||
}
|
||||
|
||||
static void extrude_mesh_edges(MeshComponent &component,
|
||||
static void extrude_mesh_edges(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float3> &offset_field,
|
||||
const AttributeOutputs &attribute_outputs)
|
||||
{
|
||||
Mesh &mesh = *component.get_for_write();
|
||||
const int orig_vert_size = mesh.totvert;
|
||||
Span<MEdge> orig_edges = mesh_edges(mesh);
|
||||
Span<MPoly> orig_polys = mesh_polys(mesh);
|
||||
const int orig_loop_size = mesh.totloop;
|
||||
|
||||
GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
|
||||
bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
|
||||
edge_evaluator.set_selection(selection_field);
|
||||
edge_evaluator.add(offset_field);
|
||||
@@ -525,7 +523,7 @@ static void extrude_mesh_edges(MeshComponent &component,
|
||||
const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
|
||||
new_vert_range.size(), duplicate_edges, orig_vert_size);
|
||||
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
|
||||
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
|
||||
@@ -658,11 +656,11 @@ static void extrude_mesh_edges(MeshComponent &component,
|
||||
|
||||
if (attribute_outputs.top_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
|
||||
mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range);
|
||||
mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range);
|
||||
}
|
||||
|
||||
BKE_mesh_runtime_clear_cache(&mesh);
|
||||
@@ -672,18 +670,17 @@ static void extrude_mesh_edges(MeshComponent &component,
|
||||
* Edges connected to one selected face are on the boundary of a region and will be duplicated into
|
||||
* a "side face". Edges inside a region will be duplicated to leave any original faces unchanged.
|
||||
*/
|
||||
static void extrude_mesh_face_regions(MeshComponent &component,
|
||||
static void extrude_mesh_face_regions(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float3> &offset_field,
|
||||
const AttributeOutputs &attribute_outputs)
|
||||
{
|
||||
Mesh &mesh = *component.get_for_write();
|
||||
const int orig_vert_size = mesh.totvert;
|
||||
Span<MEdge> orig_edges = mesh_edges(mesh);
|
||||
Span<MPoly> orig_polys = mesh_polys(mesh);
|
||||
Span<MLoop> orig_loops = mesh_loops(mesh);
|
||||
|
||||
GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
|
||||
bke::MeshFieldContext poly_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
|
||||
poly_evaluator.set_selection(selection_field);
|
||||
poly_evaluator.add(offset_field);
|
||||
@@ -905,7 +902,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
|
||||
const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
|
||||
new_vert_range.size(), boundary_edges, orig_vert_size);
|
||||
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
|
||||
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
|
||||
@@ -1039,11 +1036,11 @@ static void extrude_mesh_face_regions(MeshComponent &component,
|
||||
|
||||
if (attribute_outputs.top_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
|
||||
mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
|
||||
mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
|
||||
}
|
||||
|
||||
BKE_mesh_runtime_clear_cache(&mesh);
|
||||
@@ -1057,12 +1054,11 @@ static IndexRange selected_corner_range(Span<int> offsets, const int index)
|
||||
return IndexRange(offset, next_offset - offset);
|
||||
}
|
||||
|
||||
static void extrude_individual_mesh_faces(MeshComponent &component,
|
||||
static void extrude_individual_mesh_faces(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float3> &offset_field,
|
||||
const AttributeOutputs &attribute_outputs)
|
||||
{
|
||||
Mesh &mesh = *component.get_for_write();
|
||||
const int orig_vert_size = mesh.totvert;
|
||||
const int orig_edge_size = mesh.totedge;
|
||||
Span<MPoly> orig_polys = mesh_polys(mesh);
|
||||
@@ -1071,7 +1067,7 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
|
||||
/* Use a mesh for the result of the evaluation because the mesh is reallocated before
|
||||
* the vertices are moved, and the evaluated result might reference an attribute. */
|
||||
Array<float3> poly_offset(orig_polys.size());
|
||||
GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
|
||||
bke::MeshFieldContext poly_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
|
||||
poly_evaluator.set_selection(selection_field);
|
||||
poly_evaluator.add_with_destination(offset_field, poly_offset.as_mutable_span());
|
||||
@@ -1159,7 +1155,7 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
|
||||
}
|
||||
});
|
||||
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
|
||||
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
|
||||
@@ -1318,11 +1314,11 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
|
||||
|
||||
if (attribute_outputs.top_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
|
||||
mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
save_selection_as_attribute(
|
||||
component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
|
||||
mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
|
||||
}
|
||||
|
||||
BKE_mesh_runtime_clear_cache(&mesh);
|
||||
@@ -1359,27 +1355,26 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
params.extract_input<bool>("Individual");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_mesh()) {
|
||||
MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
switch (mode) {
|
||||
case GEO_NODE_EXTRUDE_MESH_VERTICES:
|
||||
extrude_mesh_vertices(component, selection, final_offset, attribute_outputs);
|
||||
extrude_mesh_vertices(*mesh, selection, final_offset, attribute_outputs);
|
||||
break;
|
||||
case GEO_NODE_EXTRUDE_MESH_EDGES:
|
||||
extrude_mesh_edges(component, selection, final_offset, attribute_outputs);
|
||||
extrude_mesh_edges(*mesh, selection, final_offset, attribute_outputs);
|
||||
break;
|
||||
case GEO_NODE_EXTRUDE_MESH_FACES: {
|
||||
if (extrude_individual) {
|
||||
extrude_individual_mesh_faces(component, selection, final_offset, attribute_outputs);
|
||||
extrude_individual_mesh_faces(*mesh, selection, final_offset, attribute_outputs);
|
||||
}
|
||||
else {
|
||||
extrude_mesh_face_regions(component, selection, final_offset, attribute_outputs);
|
||||
extrude_mesh_face_regions(*mesh, selection, final_offset, attribute_outputs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(BKE_mesh_is_valid(component.get_for_write()));
|
||||
BLI_assert(BKE_mesh_is_valid(mesh));
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -89,7 +89,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAtIndex final : public GeometryFieldInput {
|
||||
class FieldAtIndex final : public bke::GeometryFieldInput {
|
||||
private:
|
||||
Field<int> index_field_;
|
||||
GField value_field_;
|
||||
@@ -97,26 +97,25 @@ class FieldAtIndex final : public GeometryFieldInput {
|
||||
|
||||
public:
|
||||
FieldAtIndex(Field<int> index_field, GField value_field, eAttrDomain value_field_domain)
|
||||
: GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
|
||||
: bke::GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
|
||||
index_field_(std::move(index_field)),
|
||||
value_field_(std::move(value_field)),
|
||||
value_field_domain_(value_field_domain)
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
|
||||
const IndexMask mask) const final
|
||||
{
|
||||
const GeometryComponentFieldContext value_field_context{component, value_field_domain_};
|
||||
const bke::GeometryFieldContext value_field_context{
|
||||
context.geometry(), context.type(), value_field_domain_};
|
||||
FieldEvaluator value_evaluator{value_field_context,
|
||||
component.attribute_domain_size(value_field_domain_)};
|
||||
context.attributes()->domain_size(value_field_domain_)};
|
||||
value_evaluator.add(value_field_);
|
||||
value_evaluator.evaluate();
|
||||
const GVArray &values = value_evaluator.get_evaluated(0);
|
||||
|
||||
const GeometryComponentFieldContext index_field_context{component, domain};
|
||||
FieldEvaluator index_evaluator{index_field_context, &mask};
|
||||
FieldEvaluator index_evaluator{context, &mask};
|
||||
index_evaluator.add(index_field_);
|
||||
index_evaluator.evaluate();
|
||||
const VArray<int> indices = index_evaluator.get_evaluated<int>(0);
|
||||
|
@@ -19,24 +19,20 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Mesh"));
|
||||
}
|
||||
|
||||
static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
|
||||
static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field)
|
||||
{
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
||||
if (domain_size == 0) {
|
||||
if (mesh.totpoly == 0) {
|
||||
return;
|
||||
}
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
|
||||
fn::FieldEvaluator evaluator{field_context, mesh.totpoly};
|
||||
evaluator.add(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
Mesh *mesh = component.get_for_write();
|
||||
|
||||
mesh->mloop = (MLoop *)CustomData_duplicate_referenced_layer(
|
||||
&mesh->ldata, CD_MLOOP, mesh->totloop);
|
||||
Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
|
||||
MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
|
||||
mesh.mloop = (MLoop *)CustomData_duplicate_referenced_layer(&mesh.ldata, CD_MLOOP, mesh.totloop);
|
||||
const Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
|
||||
MutableSpan<MLoop> loops{mesh.mloop, mesh.totloop};
|
||||
|
||||
for (const int i : selection.index_range()) {
|
||||
const MPoly &poly = polys[selection[i]];
|
||||
@@ -49,7 +45,7 @@ static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selecti
|
||||
}
|
||||
}
|
||||
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain == ATTR_DOMAIN_CORNER) {
|
||||
@@ -76,11 +72,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_mesh()) {
|
||||
return;
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
mesh_flip_faces(*mesh, selection_field);
|
||||
}
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_flip_faces(mesh_component, selection_field);
|
||||
});
|
||||
|
||||
params.set_output("Mesh", std::move(geometry_set));
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_input_curve_handles_cc {
|
||||
@@ -15,31 +17,27 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Vector>(N_("Right")).field_source();
|
||||
}
|
||||
|
||||
class HandlePositionFieldInput final : public GeometryFieldInput {
|
||||
class HandlePositionFieldInput final : public bke::CurvesFieldInput {
|
||||
Field<bool> relative_;
|
||||
bool left_;
|
||||
|
||||
public:
|
||||
HandlePositionFieldInput(Field<bool> relative, bool left)
|
||||
: GeometryFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
|
||||
: bke::CurvesFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
const IndexMask mask) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
|
||||
return {};
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator(field_context, &mask);
|
||||
evaluator.add(relative_);
|
||||
evaluator.evaluate();
|
||||
const VArray<bool> relative = evaluator.get_evaluated<bool>(0);
|
||||
|
||||
const AttributeAccessor attributes = *component.attributes();
|
||||
const AttributeAccessor attributes = curves.attributes();
|
||||
|
||||
VArray<float3> positions = attributes.lookup_or_default<float3>(
|
||||
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
|
||||
@@ -69,7 +67,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
|
||||
output[i] = handles[i];
|
||||
}
|
||||
}
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return attributes.adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
|
||||
}
|
||||
|
||||
|
@@ -9,28 +9,20 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Vector>(N_("Rotation")).field_source();
|
||||
}
|
||||
|
||||
class VectorFieldInput final : public GeometryFieldInput {
|
||||
class InstanceRotationFieldInput final : public bke::InstancesFieldInput {
|
||||
public:
|
||||
VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Rotation")
|
||||
InstanceRotationFieldInput() : bke::InstancesFieldInput(CPPType::get<float3>(), "Rotation")
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain UNUSED(domain),
|
||||
GVArray get_varray_for_context(const InstancesComponent &instances,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
|
||||
component);
|
||||
|
||||
auto rotation_fn = [&](const int i) -> float3 {
|
||||
return instance_component.instance_transforms()[i].to_euler();
|
||||
return instances.instance_transforms()[i].to_euler();
|
||||
};
|
||||
|
||||
return VArray<float3>::ForFunc(instance_component.instances_num(), rotation_fn);
|
||||
return VArray<float3>::ForFunc(instances.instances_num(), rotation_fn);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -40,13 +32,13 @@ class VectorFieldInput final : public GeometryFieldInput {
|
||||
|
||||
bool is_equal_to(const fn::FieldNode &other) const override
|
||||
{
|
||||
return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
|
||||
return dynamic_cast<const InstanceRotationFieldInput *>(&other) != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
Field<float3> rotation{std::make_shared<VectorFieldInput>()};
|
||||
Field<float3> rotation{std::make_shared<InstanceRotationFieldInput>()};
|
||||
params.set_output("Rotation", std::move(rotation));
|
||||
}
|
||||
|
||||
|
@@ -9,28 +9,20 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Vector>(N_("Scale")).field_source();
|
||||
}
|
||||
|
||||
class VectorFieldInput final : public GeometryFieldInput {
|
||||
class InstanceScaleFieldInput final : public bke::InstancesFieldInput {
|
||||
public:
|
||||
VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Scale")
|
||||
InstanceScaleFieldInput() : bke::InstancesFieldInput(CPPType::get<float3>(), "Scale")
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain UNUSED(domain),
|
||||
GVArray get_varray_for_context(const InstancesComponent &instances,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
|
||||
component);
|
||||
|
||||
auto scale_fn = [&](const int i) -> float3 {
|
||||
return instance_component.instance_transforms()[i].scale();
|
||||
return instances.instance_transforms()[i].scale();
|
||||
};
|
||||
|
||||
return VArray<float3>::ForFunc(instance_component.instances_num(), scale_fn);
|
||||
return VArray<float3>::ForFunc(instances.instances_num(), scale_fn);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -40,13 +32,13 @@ class VectorFieldInput final : public GeometryFieldInput {
|
||||
|
||||
bool is_equal_to(const fn::FieldNode &other) const override
|
||||
{
|
||||
return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
|
||||
return dynamic_cast<const InstanceScaleFieldInput *>(&other) != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
Field<float3> scale{std::make_shared<VectorFieldInput>()};
|
||||
Field<float3> scale{std::make_shared<InstanceScaleFieldInput>()};
|
||||
params.set_output("Scale", std::move(scale));
|
||||
}
|
||||
|
||||
|
@@ -53,45 +53,37 @@ static Array<EdgeMapEntry> create_edge_map(const Span<MPoly> polys,
|
||||
return edge_map;
|
||||
}
|
||||
|
||||
class AngleFieldInput final : public GeometryFieldInput {
|
||||
class AngleFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
AngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Unsigned Angle Field")
|
||||
AngleFieldInput() : bke::MeshFieldInput(CPPType::get<float>(), "Unsigned Angle Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
Span<MVert> vertices{mesh.mvert, mesh.totvert};
|
||||
Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
|
||||
Span<MLoop> loops{mesh.mloop, mesh.totloop};
|
||||
Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh.totedge);
|
||||
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
|
||||
Span<MLoop> loops{mesh->mloop, mesh->totloop};
|
||||
Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
|
||||
|
||||
auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
|
||||
auto angle_fn =
|
||||
[edge_map = std::move(edge_map), vertices, polys, loops](const int i) -> float {
|
||||
if (edge_map[i].face_count != 2) {
|
||||
return 0.0f;
|
||||
}
|
||||
const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
|
||||
const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
|
||||
float3 normal_1, normal_2;
|
||||
BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1);
|
||||
BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2);
|
||||
BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], vertices.data(), normal_1);
|
||||
BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], vertices.data(), normal_2);
|
||||
return angle_normalized_v3v3(normal_1, normal_2);
|
||||
};
|
||||
|
||||
VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
|
||||
return component.attributes()->adapt_domain<float>(
|
||||
VArray<float> angles = VArray<float>::ForFunc(mesh.totedge, angle_fn);
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float>(
|
||||
std::move(angles), ATTR_DOMAIN_EDGE, domain);
|
||||
}
|
||||
|
||||
@@ -107,32 +99,25 @@ class AngleFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
class SignedAngleFieldInput final : public GeometryFieldInput {
|
||||
class SignedAngleFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
SignedAngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Signed Angle Field")
|
||||
SignedAngleFieldInput() : bke::MeshFieldInput(CPPType::get<float>(), "Signed Angle Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const Span<MVert> vertices(mesh.mvert, mesh.totvert);
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
const Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh.totedge);
|
||||
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
|
||||
Span<MLoop> loops{mesh->mloop, mesh->totloop};
|
||||
Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
|
||||
|
||||
auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
|
||||
auto angle_fn =
|
||||
[edge_map = std::move(edge_map), vertices, edges, polys, loops](const int i) -> float {
|
||||
if (edge_map[i].face_count != 2) {
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -141,18 +126,21 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
|
||||
|
||||
/* Find the normals of the 2 polys. */
|
||||
float3 poly_1_normal, poly_2_normal;
|
||||
BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, poly_1_normal);
|
||||
BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_2_normal);
|
||||
BKE_mesh_calc_poly_normal(
|
||||
&mpoly_1, &loops[mpoly_1.loopstart], vertices.data(), poly_1_normal);
|
||||
BKE_mesh_calc_poly_normal(
|
||||
&mpoly_2, &loops[mpoly_2.loopstart], vertices.data(), poly_2_normal);
|
||||
|
||||
/* Find the centerpoint of the axis edge */
|
||||
const float3 edge_centerpoint = (float3(mesh->mvert[mesh->medge[i].v1].co) +
|
||||
float3(mesh->mvert[mesh->medge[i].v2].co)) *
|
||||
const float3 edge_centerpoint = (float3(vertices[edges[i].v1].co) +
|
||||
float3(vertices[edges[i].v2].co)) *
|
||||
0.5f;
|
||||
|
||||
/* Get the centerpoint of poly 2 and subtract the edge centerpoint to get a tangent
|
||||
* normal for poly 2. */
|
||||
float3 poly_center_2;
|
||||
BKE_mesh_calc_poly_center(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_center_2);
|
||||
BKE_mesh_calc_poly_center(
|
||||
&mpoly_2, &loops[mpoly_2.loopstart], vertices.data(), poly_center_2);
|
||||
const float3 poly_2_tangent = math::normalize(poly_center_2 - edge_centerpoint);
|
||||
const float concavity = math::dot(poly_1_normal, poly_2_tangent);
|
||||
|
||||
@@ -165,8 +153,8 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
|
||||
return -angle;
|
||||
};
|
||||
|
||||
VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
|
||||
return component.attributes()->adapt_domain<float>(
|
||||
VArray<float> angles = VArray<float>::ForFunc(mesh.totedge, angle_fn);
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float>(
|
||||
std::move(angles), ATTR_DOMAIN_EDGE, domain);
|
||||
}
|
||||
|
||||
|
@@ -16,34 +16,25 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
.description(N_("The number of faces that use each edge as one of their sides"));
|
||||
}
|
||||
|
||||
class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
|
||||
class EdgeNeighborCountFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
EdgeNeighborCountFieldInput()
|
||||
: GeometryFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
|
||||
: bke::MeshFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Array<int> face_count(mesh->totedge, 0);
|
||||
for (const int i : IndexRange(mesh->totloop)) {
|
||||
face_count[mesh->mloop[i].e]++;
|
||||
}
|
||||
|
||||
return mesh_component.attributes()->adapt_domain<int>(
|
||||
VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
|
||||
Array<int> face_count(mesh.totedge, 0);
|
||||
for (const int i : IndexRange(mesh.totloop)) {
|
||||
face_count[mesh.mloop[i].e]++;
|
||||
}
|
||||
return {};
|
||||
|
||||
return bke::mesh_attributes(mesh).adapt_domain<int>(
|
||||
VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -27,45 +27,37 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
|
||||
enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
|
||||
|
||||
static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
|
||||
static VArray<int> construct_edge_vertices_gvarray(const Mesh &mesh,
|
||||
const VertexNumber vertex,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
if (domain == ATTR_DOMAIN_EDGE) {
|
||||
if (vertex == VERTEX_ONE) {
|
||||
return VArray<int>::ForFunc(mesh->totedge,
|
||||
[mesh](const int i) -> int { return mesh->medge[i].v1; });
|
||||
return VArray<int>::ForFunc(edges.size(),
|
||||
[edges](const int i) -> int { return edges[i].v1; });
|
||||
}
|
||||
return VArray<int>::ForFunc(mesh->totedge,
|
||||
[mesh](const int i) -> int { return mesh->medge[i].v2; });
|
||||
return VArray<int>::ForFunc(edges.size(), [edges](const int i) -> int { return edges[i].v2; });
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
class EdgeVerticesFieldInput final : public GeometryFieldInput {
|
||||
class EdgeVerticesFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
VertexNumber vertex_;
|
||||
|
||||
public:
|
||||
EdgeVerticesFieldInput(VertexNumber vertex)
|
||||
: GeometryFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
|
||||
: bke::MeshFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_edge_vertices_gvarray(mesh_component, vertex_, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_edge_vertices_gvarray(mesh, vertex_, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -83,51 +75,43 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
|
||||
static VArray<float3> construct_edge_positions_gvarray(const Mesh &mesh,
|
||||
const VertexNumber vertex,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Span<MVert> vertices(mesh.mvert, mesh.totvert);
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
|
||||
if (vertex == VERTEX_ONE) {
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float3>(
|
||||
VArray<float3>::ForFunc(
|
||||
mesh->totedge,
|
||||
[mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }),
|
||||
edges.size(), [vertices, edges](const int i) { return vertices[edges[i].v1].co; }),
|
||||
ATTR_DOMAIN_EDGE,
|
||||
domain);
|
||||
}
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
VArray<float3>::ForFunc(
|
||||
mesh->totedge,
|
||||
[mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float3>(
|
||||
VArray<float3>::ForFunc(edges.size(),
|
||||
[vertices, edges](const int i) { return vertices[edges[i].v2].co; }),
|
||||
ATTR_DOMAIN_EDGE,
|
||||
domain);
|
||||
}
|
||||
|
||||
class EdgePositionFieldInput final : public GeometryFieldInput {
|
||||
class EdgePositionFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
VertexNumber vertex_;
|
||||
|
||||
public:
|
||||
EdgePositionFieldInput(VertexNumber vertex)
|
||||
: GeometryFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
|
||||
: bke::MeshFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_edge_positions_gvarray(mesh_component, vertex_, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_edge_positions_gvarray(mesh, vertex_, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -16,39 +16,33 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
.description(N_("The surface area of each of the mesh's faces"));
|
||||
}
|
||||
|
||||
static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
|
||||
const eAttrDomain domain)
|
||||
static VArray<float> construct_face_area_varray(const Mesh &mesh, const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Span<MVert> vertices(mesh.mvert, mesh.totvert);
|
||||
const Span<MPoly> polygons(mesh.mpoly, mesh.totpoly);
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
auto area_fn = [mesh](const int i) -> float {
|
||||
const MPoly *mp = &mesh->mpoly[i];
|
||||
return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
|
||||
auto area_fn = [vertices, polygons, loops](const int i) -> float {
|
||||
const MPoly &poly = polygons[i];
|
||||
return BKE_mesh_calc_poly_area(&poly, &loops[poly.loopstart], vertices.data());
|
||||
};
|
||||
|
||||
return component.attributes()->adapt_domain<float>(
|
||||
VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float>(
|
||||
VArray<float>::ForFunc(polygons.size(), area_fn), ATTR_DOMAIN_FACE, domain);
|
||||
}
|
||||
|
||||
class FaceAreaFieldInput final : public GeometryFieldInput {
|
||||
class FaceAreaFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
FaceAreaFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Face Area Field")
|
||||
FaceAreaFieldInput() : bke::MeshFieldInput(CPPType::get<float>(), "Face Area Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_face_area_gvarray(mesh_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_face_area_varray(mesh, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -22,53 +22,46 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Bool>("Planar").field_source();
|
||||
}
|
||||
|
||||
class PlanarFieldInput final : public GeometryFieldInput {
|
||||
class PlanarFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
Field<float> threshold_;
|
||||
|
||||
public:
|
||||
PlanarFieldInput(Field<float> threshold)
|
||||
: GeometryFieldInput(CPPType::get<bool>(), "Planar"), threshold_(threshold)
|
||||
: bke::MeshFieldInput(CPPType::get<bool>(), "Planar"), threshold_(threshold)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
[[maybe_unused]] IndexMask mask) const final
|
||||
IndexMask /*mask*/) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const Span<MVert> vertices(mesh.mvert, mesh.totvert);
|
||||
const Span<MPoly> polygons(mesh.mpoly, mesh.totpoly);
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_FACE};
|
||||
fn::FieldEvaluator evaluator{context, mesh->totpoly};
|
||||
bke::MeshFieldContext context{mesh, ATTR_DOMAIN_FACE};
|
||||
fn::FieldEvaluator evaluator{context, polygons.size()};
|
||||
evaluator.add(threshold_);
|
||||
evaluator.evaluate();
|
||||
const VArray<float> thresholds = evaluator.get_evaluated<float>(0);
|
||||
|
||||
Span<float3> poly_normals{(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly};
|
||||
Span<float3> poly_normals{(float3 *)BKE_mesh_poly_normals_ensure(&mesh), polygons.size()};
|
||||
|
||||
auto planar_fn = [mesh, thresholds, poly_normals](const int i_poly) -> bool {
|
||||
if (mesh->mpoly[i_poly].totloop <= 3) {
|
||||
auto planar_fn = [vertices, polygons, loops, thresholds, poly_normals](const int i) -> bool {
|
||||
const MPoly &poly = polygons[i];
|
||||
if (poly.totloop <= 3) {
|
||||
return true;
|
||||
}
|
||||
const int loopstart = mesh->mpoly[i_poly].loopstart;
|
||||
const int loops = mesh->mpoly[i_poly].totloop;
|
||||
Span<MLoop> poly_loops(&mesh->mloop[loopstart], loops);
|
||||
float3 reference_normal = poly_normals[i_poly];
|
||||
const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
|
||||
float3 reference_normal = poly_normals[i];
|
||||
|
||||
float min = FLT_MAX;
|
||||
float max = -FLT_MAX;
|
||||
|
||||
for (const int i_loop : poly_loops.index_range()) {
|
||||
const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
|
||||
const float3 vert = vertices[poly_loops[i_loop].v].co;
|
||||
float dot = math::dot(reference_normal, vert);
|
||||
if (dot > max) {
|
||||
max = dot;
|
||||
@@ -77,11 +70,11 @@ class PlanarFieldInput final : public GeometryFieldInput {
|
||||
min = dot;
|
||||
}
|
||||
}
|
||||
return max - min < thresholds[i_poly] / 2.0f;
|
||||
return max - min < thresholds[i] / 2.0f;
|
||||
};
|
||||
|
||||
return component.attributes()->adapt_domain<bool>(
|
||||
VArray<bool>::ForFunc(mesh->totpoly, planar_fn), ATTR_DOMAIN_FACE, domain);
|
||||
return bke::mesh_attributes(mesh).adapt_domain<bool>(
|
||||
VArray<bool>::ForFunc(polygons.size(), planar_fn), ATTR_DOMAIN_FACE, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -19,48 +19,42 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
.description(N_("Number of faces which share an edge with the face"));
|
||||
}
|
||||
|
||||
static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
|
||||
const eAttrDomain domain)
|
||||
static VArray<int> construct_neighbor_count_varray(const Mesh &mesh, const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
const Span<MPoly> polygons(mesh.mpoly, mesh.totpoly);
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
Array<int> edge_count(edges.size(), 0);
|
||||
for (const int i : loops.index_range()) {
|
||||
edge_count[loops[i].e]++;
|
||||
}
|
||||
|
||||
Array<int> edge_count(mesh->totedge, 0);
|
||||
for (const int i : IndexRange(mesh->totloop)) {
|
||||
edge_count[mesh->mloop[i].e]++;
|
||||
}
|
||||
|
||||
Array<int> poly_count(mesh->totpoly, 0);
|
||||
for (const int poly_num : IndexRange(mesh->totpoly)) {
|
||||
MPoly &poly = mesh->mpoly[poly_num];
|
||||
for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) {
|
||||
poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1;
|
||||
Array<int> poly_count(polygons.size(), 0);
|
||||
for (const int poly_i : polygons.index_range()) {
|
||||
const MPoly &poly = polygons[poly_i];
|
||||
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
|
||||
poly_count[poly_i] += edge_count[loop.e] - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return component.attributes()->adapt_domain<int>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<int>(
|
||||
VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
|
||||
}
|
||||
|
||||
class FaceNeighborCountFieldInput final : public GeometryFieldInput {
|
||||
class FaceNeighborCountFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
FaceNeighborCountFieldInput()
|
||||
: GeometryFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
|
||||
: bke::MeshFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_neighbor_count_gvarray(mesh_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_neighbor_count_varray(mesh, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -75,37 +69,28 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
|
||||
const eAttrDomain domain)
|
||||
static VArray<int> construct_vertex_count_varray(const Mesh &mesh, const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return component.attributes()->adapt_domain<int>(
|
||||
VArray<int>::ForFunc(mesh->totpoly,
|
||||
[mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
|
||||
const Span<MPoly> polygons(mesh.mpoly, mesh.totpoly);
|
||||
return bke::mesh_attributes(mesh).adapt_domain<int>(
|
||||
VArray<int>::ForFunc(polygons.size(),
|
||||
[polygons](const int i) -> float { return polygons[i].totloop; }),
|
||||
ATTR_DOMAIN_FACE,
|
||||
domain);
|
||||
}
|
||||
|
||||
class FaceVertexCountFieldInput final : public GeometryFieldInput {
|
||||
class FaceVertexCountFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
|
||||
FaceVertexCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Count Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_vertex_count_gvarray(mesh_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_vertex_count_varray(mesh, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -22,39 +22,32 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
.description(N_("The total number of mesh islands"));
|
||||
}
|
||||
|
||||
class IslandFieldInput final : public GeometryFieldInput {
|
||||
class IslandFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index")
|
||||
IslandFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Island Index")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
|
||||
DisjointSet islands(mesh.totvert);
|
||||
for (const int i : edges.index_range()) {
|
||||
islands.join(edges[i].v1, edges[i].v2);
|
||||
}
|
||||
|
||||
DisjointSet islands(mesh->totvert);
|
||||
for (const int i : IndexRange(mesh->totedge)) {
|
||||
islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
|
||||
}
|
||||
|
||||
Array<int> output(mesh->totvert);
|
||||
Array<int> output(mesh.totvert);
|
||||
VectorSet<int> ordered_roots;
|
||||
for (const int i : IndexRange(mesh->totvert)) {
|
||||
for (const int i : IndexRange(mesh.totvert)) {
|
||||
const int64_t root = islands.find_root(i);
|
||||
output[i] = ordered_roots.index_of_or_add(root);
|
||||
}
|
||||
|
||||
return mesh_component.attributes()->adapt_domain<int>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<int>(
|
||||
VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
|
||||
}
|
||||
|
||||
@@ -70,39 +63,32 @@ class IslandFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
class IslandCountFieldInput final : public GeometryFieldInput {
|
||||
class IslandCountFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
IslandCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Count")
|
||||
IslandCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Island Count")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
|
||||
DisjointSet islands(mesh->totvert);
|
||||
for (const int i : IndexRange(mesh->totedge)) {
|
||||
islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
|
||||
DisjointSet islands(mesh.totvert);
|
||||
for (const int i : edges.index_range()) {
|
||||
islands.join(edges[i].v1, edges[i].v2);
|
||||
}
|
||||
|
||||
Set<int> island_list;
|
||||
for (const int i_vert : IndexRange(mesh->totvert)) {
|
||||
for (const int i_vert : IndexRange(mesh.totvert)) {
|
||||
const int64_t root = islands.find_root(i_vert);
|
||||
island_list.add(root);
|
||||
}
|
||||
|
||||
return VArray<int>::ForSingle(island_list.size(),
|
||||
mesh_component.attribute_domain_size(domain));
|
||||
bke::mesh_attributes(mesh).domain_size(domain));
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -20,41 +20,33 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
.description(N_("Number of faces that contain the vertex"));
|
||||
}
|
||||
|
||||
static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
|
||||
const eAttrDomain domain)
|
||||
static VArray<int> construct_vertex_count_gvarray(const Mesh &mesh, const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<int> vertices(mesh->totvert, 0);
|
||||
for (const int i : IndexRange(mesh->totedge)) {
|
||||
vertices[mesh->medge[i].v1]++;
|
||||
vertices[mesh->medge[i].v2]++;
|
||||
Array<int> counts(mesh.totvert, 0);
|
||||
for (const int i : edges.index_range()) {
|
||||
counts[edges[i].v1]++;
|
||||
counts[edges[i].v2]++;
|
||||
}
|
||||
return VArray<int>::ForContainer(std::move(vertices));
|
||||
return VArray<int>::ForContainer(std::move(counts));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
class VertexCountFieldInput final : public GeometryFieldInput {
|
||||
class VertexCountFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
VertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
|
||||
VertexCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Count Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_vertex_count_gvarray(mesh_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_vertex_count_gvarray(mesh, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
@@ -69,18 +61,14 @@ class VertexCountFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
|
||||
const eAttrDomain domain)
|
||||
static VArray<int> construct_face_count_gvarray(const Mesh &mesh, const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<int> vertices(mesh->totvert, 0);
|
||||
for (const int i : IndexRange(mesh->totloop)) {
|
||||
int vertex = mesh->mloop[i].v;
|
||||
Array<int> vertices(mesh.totvert, 0);
|
||||
for (const int i : loops.index_range()) {
|
||||
int vertex = loops[i].v;
|
||||
vertices[vertex]++;
|
||||
}
|
||||
return VArray<int>::ForContainer(std::move(vertices));
|
||||
@@ -88,22 +76,18 @@ static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
|
||||
return {};
|
||||
}
|
||||
|
||||
class VertexFaceCountFieldInput final : public GeometryFieldInput {
|
||||
class VertexFaceCountFieldInput final : public bke::MeshFieldInput {
|
||||
public:
|
||||
VertexFaceCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
|
||||
VertexFaceCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_face_count_gvarray(mesh_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_face_count_gvarray(mesh, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -28,10 +28,10 @@ typedef std::pair<float, int> VertPriority;
|
||||
struct EdgeVertMap {
|
||||
Array<Vector<int>> edges_by_vertex_map;
|
||||
|
||||
EdgeVertMap(const Mesh *mesh)
|
||||
EdgeVertMap(const Mesh &mesh)
|
||||
{
|
||||
const Span<MEdge> edges{mesh->medge, mesh->totedge};
|
||||
edges_by_vertex_map.reinitialize(mesh->totvert);
|
||||
const Span<MEdge> edges{mesh.medge, mesh.totedge};
|
||||
edges_by_vertex_map.reinitialize(mesh.totvert);
|
||||
for (const int edge_i : edges.index_range()) {
|
||||
const MEdge &edge = edges[edge_i];
|
||||
edges_by_vertex_map[edge.v1].append(edge_i);
|
||||
@@ -40,16 +40,16 @@ struct EdgeVertMap {
|
||||
}
|
||||
};
|
||||
|
||||
static void shortest_paths(const Mesh *mesh,
|
||||
static void shortest_paths(const Mesh &mesh,
|
||||
EdgeVertMap &maps,
|
||||
const IndexMask end_selection,
|
||||
const VArray<float> &input_cost,
|
||||
MutableSpan<int> r_next_index,
|
||||
MutableSpan<float> r_cost)
|
||||
{
|
||||
const Span<MVert> verts{mesh->mvert, mesh->totvert};
|
||||
const Span<MEdge> edges{mesh->medge, mesh->totedge};
|
||||
Array<bool> visited(mesh->totvert, false);
|
||||
const Span<MVert> verts{mesh.mvert, mesh.totvert};
|
||||
const Span<MEdge> edges{mesh.medge, mesh.totedge};
|
||||
Array<bool> visited(mesh.totvert, false);
|
||||
|
||||
std::priority_queue<VertPriority, std::vector<VertPriority>, std::greater<VertPriority>> queue;
|
||||
|
||||
@@ -84,46 +84,38 @@ static void shortest_paths(const Mesh *mesh,
|
||||
}
|
||||
}
|
||||
|
||||
class ShortestEdgePathsNextVertFieldInput final : public GeometryFieldInput {
|
||||
class ShortestEdgePathsNextVertFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
Field<bool> end_selection_;
|
||||
Field<float> cost_;
|
||||
|
||||
public:
|
||||
ShortestEdgePathsNextVertFieldInput(Field<bool> end_selection, Field<float> cost)
|
||||
: GeometryFieldInput(CPPType::get<int>(), "Shortest Edge Paths Next Vertex Field"),
|
||||
: bke::MeshFieldInput(CPPType::get<int>(), "Shortest Edge Paths Next Vertex Field"),
|
||||
end_selection_(end_selection),
|
||||
cost_(cost)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
[[maybe_unused]] IndexMask mask) const final
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator edge_evaluator{edge_context, mesh->totedge};
|
||||
bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
|
||||
edge_evaluator.add(cost_);
|
||||
edge_evaluator.evaluate();
|
||||
const VArray<float> input_cost = edge_evaluator.get_evaluated<float>(0);
|
||||
|
||||
GeometryComponentFieldContext point_context{component, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator point_evaluator{point_context, mesh->totvert};
|
||||
bke::MeshFieldContext point_context{mesh, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator point_evaluator{point_context, mesh.totvert};
|
||||
point_evaluator.add(end_selection_);
|
||||
point_evaluator.evaluate();
|
||||
const IndexMask end_selection = point_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
Array<int> next_index(mesh->totvert, -1);
|
||||
Array<float> cost(mesh->totvert, FLT_MAX);
|
||||
Array<int> next_index(mesh.totvert, -1);
|
||||
Array<float> cost(mesh.totvert, FLT_MAX);
|
||||
|
||||
if (!end_selection.is_empty()) {
|
||||
EdgeVertMap maps(mesh);
|
||||
@@ -136,7 +128,7 @@ class ShortestEdgePathsNextVertFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
}
|
||||
});
|
||||
return component.attributes()->adapt_domain<int>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<int>(
|
||||
VArray<int>::ForContainer(std::move(next_index)), ATTR_DOMAIN_POINT, domain);
|
||||
}
|
||||
|
||||
@@ -156,46 +148,38 @@ class ShortestEdgePathsNextVertFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
};
|
||||
|
||||
class ShortestEdgePathsCostFieldInput final : public GeometryFieldInput {
|
||||
class ShortestEdgePathsCostFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
Field<bool> end_selection_;
|
||||
Field<float> cost_;
|
||||
|
||||
public:
|
||||
ShortestEdgePathsCostFieldInput(Field<bool> end_selection, Field<float> cost)
|
||||
: GeometryFieldInput(CPPType::get<float>(), "Shortest Edge Paths Cost Field"),
|
||||
: bke::MeshFieldInput(CPPType::get<float>(), "Shortest Edge Paths Cost Field"),
|
||||
end_selection_(end_selection),
|
||||
cost_(cost)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
[[maybe_unused]] IndexMask mask) const final
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator edge_evaluator{edge_context, mesh->totedge};
|
||||
bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
|
||||
edge_evaluator.add(cost_);
|
||||
edge_evaluator.evaluate();
|
||||
const VArray<float> input_cost = edge_evaluator.get_evaluated<float>(0);
|
||||
|
||||
GeometryComponentFieldContext point_context{component, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator point_evaluator{point_context, mesh->totvert};
|
||||
bke::MeshFieldContext point_context{mesh, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator point_evaluator{point_context, mesh.totvert};
|
||||
point_evaluator.add(end_selection_);
|
||||
point_evaluator.evaluate();
|
||||
const IndexMask end_selection = point_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
Array<int> next_index(mesh->totvert, -1);
|
||||
Array<float> cost(mesh->totvert, FLT_MAX);
|
||||
Array<int> next_index(mesh.totvert, -1);
|
||||
Array<float> cost(mesh.totvert, FLT_MAX);
|
||||
|
||||
if (!end_selection.is_empty()) {
|
||||
EdgeVertMap maps(mesh);
|
||||
@@ -208,7 +192,7 @@ class ShortestEdgePathsCostFieldInput final : public GeometryFieldInput {
|
||||
}
|
||||
}
|
||||
});
|
||||
return component.attributes()->adapt_domain<float>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float>(
|
||||
VArray<float>::ForContainer(std::move(cost)), ATTR_DOMAIN_POINT, domain);
|
||||
}
|
||||
|
||||
|
@@ -16,15 +16,9 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
* Spline Count
|
||||
*/
|
||||
|
||||
static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component,
|
||||
static VArray<int> construct_curve_point_count_gvarray(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
if (!component.has_curves()) {
|
||||
return {};
|
||||
}
|
||||
const Curves &curves_id = *component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
auto count_fn = [curves](int64_t i) { return curves.points_for_curve(i).size(); };
|
||||
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
@@ -32,29 +26,24 @@ static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &com
|
||||
}
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
VArray<int> count = VArray<int>::ForFunc(curves.curves_num(), count_fn);
|
||||
return component.attributes()->adapt_domain<int>(
|
||||
std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
|
||||
return curves.adapt_domain<int>(std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
class SplineCountFieldInput final : public GeometryFieldInput {
|
||||
class SplineCountFieldInput final : public bke::CurvesFieldInput {
|
||||
public:
|
||||
SplineCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Point Count")
|
||||
SplineCountFieldInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Spline Point Count")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
return construct_curve_point_count_gvarray(curve_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_curve_point_count_gvarray(curves, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -63,19 +63,12 @@ static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curve
|
||||
return results;
|
||||
}
|
||||
|
||||
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
|
||||
static VArray<float3> construct_curve_tangent_gvarray(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
if (!component.has_curves()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Curves &curves_id = *component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
const VArray<int8_t> types = curves.curve_types();
|
||||
if (curves.is_single_type(CURVE_TYPE_POLY)) {
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return curves.adapt_domain<float3>(
|
||||
VArray<float3>::ForSpan(curves.evaluated_tangents()), ATTR_DOMAIN_POINT, domain);
|
||||
}
|
||||
|
||||
@@ -86,29 +79,25 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
|
||||
}
|
||||
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return curves.adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(tangents)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class TangentFieldInput final : public GeometryFieldInput {
|
||||
class TangentFieldInput final : public bke::CurvesFieldInput {
|
||||
public:
|
||||
TangentFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Tangent node")
|
||||
TangentFieldInput() : bke::CurvesFieldInput(CPPType::get<float3>(), "Tangent node")
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
|
||||
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
|
||||
return construct_curve_tangent_gvarray(curve_component, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_curve_tangent_gvarray(curves, domain);
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
|
@@ -57,7 +57,7 @@ static void add_instances_from_component(
|
||||
VArray<float3> rotations;
|
||||
VArray<float3> scales;
|
||||
|
||||
GeometryComponentFieldContext field_context{src_component, domain};
|
||||
bke::GeometryFieldContext field_context{src_component, domain};
|
||||
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
|
||||
fn::FieldEvaluator evaluator{field_context, domain_num};
|
||||
evaluator.set_selection(selection_field);
|
||||
|
@@ -29,10 +29,8 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
|
||||
{
|
||||
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
|
||||
const int domain_size = instances.instances_num();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
const bke::InstancesFieldContext context{instances};
|
||||
fn::FieldEvaluator evaluator{context, instances.instances_num()};
|
||||
evaluator.set_selection(std::move(selection_field));
|
||||
evaluator.add(std::move(position_field));
|
||||
evaluator.add(std::move(radius_field));
|
||||
|
@@ -83,31 +83,33 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
||||
}
|
||||
}
|
||||
|
||||
class InterpolateDomain final : public GeometryFieldInput {
|
||||
class InterpolateDomain final : public bke::GeometryFieldInput {
|
||||
private:
|
||||
GField src_field_;
|
||||
eAttrDomain src_domain_;
|
||||
|
||||
public:
|
||||
InterpolateDomain(GField field, eAttrDomain domain)
|
||||
: GeometryFieldInput(field.cpp_type(), "Interpolate Domain"),
|
||||
: bke::GeometryFieldInput(field.cpp_type(), "Interpolate Domain"),
|
||||
src_field_(std::move(field)),
|
||||
src_domain_(domain)
|
||||
{
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask /* mask */) const final
|
||||
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
|
||||
IndexMask /*mask*/) const final
|
||||
{
|
||||
const GeometryComponentFieldContext context{component, src_domain_};
|
||||
const int64_t src_domain_size = component.attribute_domain_size(src_domain_);
|
||||
const bke::AttributeAccessor attributes = *context.attributes();
|
||||
|
||||
const bke::GeometryFieldContext other_domain_context{
|
||||
context.geometry(), context.type(), src_domain_};
|
||||
const int64_t src_domain_size = attributes.domain_size(src_domain_);
|
||||
GArray values(src_field_.cpp_type(), src_domain_size);
|
||||
FieldEvaluator value_evaluator{context, src_domain_size};
|
||||
FieldEvaluator value_evaluator{other_domain_context, src_domain_size};
|
||||
value_evaluator.add_with_destination(src_field_, values.as_mutable_span());
|
||||
value_evaluator.evaluate();
|
||||
return component.attributes()->adapt_domain(
|
||||
GVArray::ForGArray(std::move(values)), src_domain_, domain);
|
||||
return attributes.adapt_domain(
|
||||
GVArray::ForGArray(std::move(values)), src_domain_, context.domain());
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -40,29 +40,28 @@ static void select_mesh_by_material(const Mesh &mesh,
|
||||
});
|
||||
}
|
||||
|
||||
class MaterialSelectionFieldInput final : public GeometryFieldInput {
|
||||
class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
|
||||
Material *material_;
|
||||
|
||||
public:
|
||||
MaterialSelectionFieldInput(Material *material)
|
||||
: GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
|
||||
: bke::GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"),
|
||||
material_(material)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
|
||||
const IndexMask mask) const final
|
||||
{
|
||||
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
if (context.type() != GEO_COMPONENT_TYPE_MESH) {
|
||||
return {};
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
const Mesh *mesh = context.mesh();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const eAttrDomain domain = context.domain();
|
||||
if (domain == ATTR_DOMAIN_FACE) {
|
||||
Array<bool> selection(mask.min_array_size());
|
||||
select_mesh_by_material(*mesh, material_, mask, selection);
|
||||
@@ -71,7 +70,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
|
||||
|
||||
Array<bool> selection(mesh->totpoly);
|
||||
select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
|
||||
return mesh_component.attributes()->adapt_domain<bool>(
|
||||
return bke::mesh_attributes(*mesh).adapt_domain<bool>(
|
||||
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
|
||||
|
||||
return nullptr;
|
||||
|
@@ -1,5 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "GEO_mesh_merge_by_distance.hh"
|
||||
#include "GEO_point_merge_by_distance.hh"
|
||||
|
||||
@@ -35,13 +38,12 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_points,
|
||||
static PointCloud *pointcloud_merge_by_distance(const PointCloud &src_points,
|
||||
const float merge_distance,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
const int src_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{context, src_num};
|
||||
bke::PointCloudFieldContext context{src_points};
|
||||
FieldEvaluator evaluator{context, src_points.totpoint};
|
||||
evaluator.add(selection_field);
|
||||
evaluator.evaluate();
|
||||
|
||||
@@ -50,31 +52,28 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return geometry::point_merge_by_distance(*src_points.get_for_read(), merge_distance, selection);
|
||||
return geometry::point_merge_by_distance(src_points, merge_distance, selection);
|
||||
}
|
||||
|
||||
static std::optional<Mesh *> mesh_merge_by_distance_connected(const MeshComponent &mesh_component,
|
||||
static std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
|
||||
const float merge_distance,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
Array<bool> selection(src_num);
|
||||
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{context, src_num};
|
||||
Array<bool> selection(mesh.totvert);
|
||||
bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{context, mesh.totvert};
|
||||
evaluator.add_with_destination(selection_field, selection.as_mutable_span());
|
||||
evaluator.evaluate();
|
||||
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
return geometry::mesh_merge_by_distance_connected(mesh, selection, merge_distance, false);
|
||||
}
|
||||
|
||||
static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mesh_component,
|
||||
static std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
|
||||
const float merge_distance,
|
||||
const Field<bool> &selection_field)
|
||||
{
|
||||
const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{context, src_num};
|
||||
bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator evaluator{context, mesh.totvert};
|
||||
evaluator.add(selection_field);
|
||||
evaluator.evaluate();
|
||||
|
||||
@@ -83,7 +82,6 @@ static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mes
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
return geometry::mesh_merge_by_distance_all(mesh, selection, merge_distance);
|
||||
}
|
||||
|
||||
@@ -98,22 +96,20 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
const float merge_distance = params.extract_input<float>("Distance");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_pointcloud()) {
|
||||
PointCloud *result = pointcloud_merge_by_distance(
|
||||
*geometry_set.get_component_for_read<PointCloudComponent>(), merge_distance, selection);
|
||||
if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
|
||||
PointCloud *result = pointcloud_merge_by_distance(*pointcloud, merge_distance, selection);
|
||||
if (result) {
|
||||
geometry_set.replace_pointcloud(result);
|
||||
}
|
||||
}
|
||||
if (geometry_set.has_mesh()) {
|
||||
const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
|
||||
std::optional<Mesh *> result;
|
||||
switch (mode) {
|
||||
case GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL:
|
||||
result = mesh_merge_by_distance_all(component, merge_distance, selection);
|
||||
result = mesh_merge_by_distance_all(*mesh, merge_distance, selection);
|
||||
break;
|
||||
case GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED:
|
||||
result = mesh_merge_by_distance_connected(component, merge_distance, selection);
|
||||
result = mesh_merge_by_distance_connected(*mesh, merge_distance, selection);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_mesh_to_curve.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
@@ -24,9 +26,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
GeometryComponentFieldContext context{component, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_EDGE)};
|
||||
bke::MeshFieldContext context{*mesh, ATTR_DOMAIN_EDGE};
|
||||
fn::FieldEvaluator evaluator{context, mesh->totedge};
|
||||
evaluator.add(params.get_input<Field<bool>>("Selection"));
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
|
@@ -60,18 +60,18 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
|
||||
Field<bool> &selection_field,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
|
||||
if (mesh_component == nullptr) {
|
||||
const Mesh *mesh = geometry_set.get_mesh_for_read();
|
||||
if (mesh == nullptr) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
return;
|
||||
}
|
||||
GeometryComponentFieldContext field_context{*mesh_component, domain};
|
||||
const int domain_num = mesh_component->attribute_domain_size(domain);
|
||||
if (domain_num == 0) {
|
||||
const int domain_size = bke::mesh_attributes(*mesh).domain_size(domain);
|
||||
if (domain_size == 0) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
return;
|
||||
}
|
||||
fn::FieldEvaluator evaluator{field_context, domain_num};
|
||||
bke::MeshFieldContext field_context{*mesh, domain};
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
evaluator.set_selection(selection_field);
|
||||
/* Evaluating directly into the point cloud doesn't work because we are not using the full
|
||||
* "min_array_size" array but compressing the selected elements into the final array with no
|
||||
@@ -83,16 +83,15 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
|
||||
|
||||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
|
||||
geometry_set.replace_pointcloud(pointcloud);
|
||||
MutableAttributeAccessor pointcloud_attributes = bke::pointcloud_attributes_for_write(
|
||||
*pointcloud);
|
||||
MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write(*pointcloud);
|
||||
|
||||
GSpanAttributeWriter position = pointcloud_attributes.lookup_or_add_for_write_only_span(
|
||||
GSpanAttributeWriter position = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
|
||||
materialize_compressed_to_uninitialized_threaded(
|
||||
evaluator.get_evaluated(0), selection, position.span);
|
||||
position.finish();
|
||||
|
||||
GSpanAttributeWriter radius = pointcloud_attributes.lookup_or_add_for_write_only_span(
|
||||
GSpanAttributeWriter radius = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
"radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
|
||||
materialize_compressed_to_uninitialized_threaded(
|
||||
evaluator.get_evaluated(1), selection, radius.span);
|
||||
@@ -103,11 +102,13 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
|
||||
{GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
|
||||
attributes.remove("position");
|
||||
|
||||
const AttributeAccessor src_attributes = bke::mesh_attributes(*mesh);
|
||||
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
const eCustomDataType data_type = entry.value.data_type;
|
||||
GVArray src = mesh_component->attributes()->lookup_or_default(attribute_id, domain, data_type);
|
||||
GSpanAttributeWriter dst = pointcloud_attributes.lookup_or_add_for_write_only_span(
|
||||
GVArray src = src_attributes.lookup_or_default(attribute_id, domain, data_type);
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
if (dst && src) {
|
||||
materialize_compressed_to_uninitialized_threaded(src, selection, dst.span);
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
@@ -22,21 +24,18 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
|
||||
Field<bool> &selection_field)
|
||||
{
|
||||
const PointCloudComponent *point_component =
|
||||
geometry_set.get_component_for_read<PointCloudComponent>();
|
||||
if (point_component == nullptr) {
|
||||
const PointCloud *points = geometry_set.get_pointcloud_for_read();
|
||||
if (points == nullptr) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
return;
|
||||
}
|
||||
if (points->totpoint == 0) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
|
||||
const int domain_num = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
if (domain_num == 0) {
|
||||
geometry_set.remove_geometry_during_modify();
|
||||
return;
|
||||
}
|
||||
|
||||
fn::FieldEvaluator selection_evaluator{field_context, domain_num};
|
||||
bke::PointCloudFieldContext field_context{*points};
|
||||
fn::FieldEvaluator selection_evaluator{field_context, points->totpoint};
|
||||
selection_evaluator.add(selection_field);
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
@@ -47,16 +46,16 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
|
||||
|
||||
Mesh *mesh = BKE_mesh_new_nomain(selection.size(), 0, 0, 0, 0);
|
||||
geometry_set.replace_mesh(mesh);
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
|
||||
const AttributeAccessor src_attributes = bke::pointcloud_attributes(*points);
|
||||
MutableAttributeAccessor dst_attributes = bke::mesh_attributes_for_write(*mesh);
|
||||
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
const eCustomDataType data_type = entry.value.data_type;
|
||||
GVArray src = point_component->attributes()->lookup_or_default(
|
||||
GVArray src = src_attributes.lookup_or_default(attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
GSpanAttributeWriter dst =
|
||||
mesh_component.attributes_for_write()->lookup_or_add_for_write_only_span(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
if (dst && src) {
|
||||
src.materialize_compressed_to_uninitialized(selection, dst.span.data());
|
||||
dst.finish();
|
||||
|
@@ -170,7 +170,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms,
|
||||
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
|
||||
|
||||
Field<float> radius_field = params.get_input<Field<float>>("Radius");
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
bke::GeometryFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
const int domain_num = component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
|
||||
r_positions.resize(r_positions.size() + domain_num);
|
||||
|
@@ -208,7 +208,7 @@ class RaycastFunction : public fn::MultiFunction {
|
||||
GeometryNodeRaycastMapMode mapping_;
|
||||
|
||||
/** The field for data evaluated on the target geometry. */
|
||||
std::optional<GeometryComponentFieldContext> target_context_;
|
||||
std::optional<bke::MeshFieldContext> target_context_;
|
||||
std::unique_ptr<FieldEvaluator> target_evaluator_;
|
||||
const GVArray *target_data_ = nullptr;
|
||||
|
||||
@@ -310,9 +310,9 @@ class RaycastFunction : public fn::MultiFunction {
|
||||
if (!src_field) {
|
||||
return;
|
||||
}
|
||||
const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
|
||||
target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
|
||||
const int domain_size = mesh_component.attribute_domain_size(domain_);
|
||||
const Mesh &mesh = *target_.get_mesh_for_read();
|
||||
target_context_.emplace(bke::MeshFieldContext{mesh, domain_});
|
||||
const int domain_size = bke::mesh_attributes(mesh).domain_size(domain_);
|
||||
target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_size);
|
||||
target_evaluator_->add(std::move(src_field));
|
||||
target_evaluator_->evaluate();
|
||||
|
@@ -18,10 +18,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
|
||||
static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component)
|
||||
{
|
||||
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
|
||||
const int domain_num = instances_component.instances_num();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_num};
|
||||
const bke::InstancesFieldContext context{instances_component};
|
||||
fn::FieldEvaluator evaluator{context, instances_component.instances_num()};
|
||||
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
|
||||
evaluator.add(params.extract_input<Field<float3>>("Rotation"));
|
||||
evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
|
||||
|
@@ -288,13 +288,12 @@ static AxisScaleParams evaluate_axis_scale_fields(FieldEvaluator &evaluator,
|
||||
return out;
|
||||
}
|
||||
|
||||
static void scale_faces_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
|
||||
static void scale_faces_on_axis(Mesh &mesh, const AxisScaleFields &fields)
|
||||
{
|
||||
Mesh &mesh = *mesh_component.get_for_write();
|
||||
mesh.mvert = static_cast<MVert *>(
|
||||
CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
|
||||
|
||||
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator evaluator{field_context, mesh.totpoly};
|
||||
AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
|
||||
|
||||
@@ -314,13 +313,12 @@ static UniformScaleParams evaluate_uniform_scale_fields(FieldEvaluator &evaluato
|
||||
return out;
|
||||
}
|
||||
|
||||
static void scale_faces_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
|
||||
static void scale_faces_uniformly(Mesh &mesh, const UniformScaleFields &fields)
|
||||
{
|
||||
Mesh &mesh = *mesh_component.get_for_write();
|
||||
mesh.mvert = static_cast<MVert *>(
|
||||
CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
|
||||
|
||||
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator evaluator{field_context, mesh.totpoly};
|
||||
UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
|
||||
|
||||
@@ -364,13 +362,12 @@ static void get_edge_vertices(const Mesh &mesh, int edge_index, VectorSet<int> &
|
||||
r_vertex_indices.add(edge.v2);
|
||||
}
|
||||
|
||||
static void scale_edges_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
|
||||
static void scale_edges_uniformly(Mesh &mesh, const UniformScaleFields &fields)
|
||||
{
|
||||
Mesh &mesh = *mesh_component.get_for_write();
|
||||
mesh.mvert = static_cast<MVert *>(
|
||||
CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
|
||||
|
||||
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator evaluator{field_context, mesh.totedge};
|
||||
UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
|
||||
|
||||
@@ -378,13 +375,12 @@ static void scale_edges_uniformly(MeshComponent &mesh_component, const UniformSc
|
||||
scale_vertex_islands_uniformly(mesh, island, params, get_edge_vertices);
|
||||
}
|
||||
|
||||
static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
|
||||
static void scale_edges_on_axis(Mesh &mesh, const AxisScaleFields &fields)
|
||||
{
|
||||
Mesh &mesh = *mesh_component.get_for_write();
|
||||
mesh.mvert = static_cast<MVert *>(
|
||||
CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
|
||||
|
||||
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator evaluator{field_context, mesh.totedge};
|
||||
AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
|
||||
|
||||
@@ -410,42 +406,38 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
|
||||
geometry.modify_geometry_sets([&](GeometrySet &geometry) {
|
||||
if (!geometry.has_mesh()) {
|
||||
return;
|
||||
}
|
||||
MeshComponent &mesh_component = geometry.get_component_for_write<MeshComponent>();
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
switch (scale_mode) {
|
||||
case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
|
||||
scale_faces_uniformly(mesh_component, {selection_field, scale_field, center_field});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
|
||||
scale_faces_on_axis(mesh_component,
|
||||
{selection_field, scale_field, center_field, axis_field});
|
||||
break;
|
||||
if (Mesh *mesh = geometry.get_mesh_for_write()) {
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
switch (scale_mode) {
|
||||
case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
|
||||
scale_faces_uniformly(*mesh, {selection_field, scale_field, center_field});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
|
||||
scale_faces_on_axis(*mesh, {selection_field, scale_field, center_field, axis_field});
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
switch (scale_mode) {
|
||||
case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
|
||||
scale_edges_uniformly(mesh_component, {selection_field, scale_field, center_field});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
|
||||
scale_edges_on_axis(mesh_component,
|
||||
{selection_field, scale_field, center_field, axis_field});
|
||||
break;
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
switch (scale_mode) {
|
||||
case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
|
||||
scale_edges_uniformly(*mesh, {selection_field, scale_field, center_field});
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
|
||||
scale_edges_on_axis(*mesh, {selection_field, scale_field, center_field, axis_field});
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -21,9 +21,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
|
||||
static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component)
|
||||
{
|
||||
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, instances_component.instances_num()};
|
||||
const bke::InstancesFieldContext context{instances_component};
|
||||
fn::FieldEvaluator evaluator{context, instances_component.instances_num()};
|
||||
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
|
||||
evaluator.add(params.extract_input<Field<float3>>("Scale"));
|
||||
evaluator.add(params.extract_input<Field<float3>>("Center"));
|
||||
|
@@ -68,19 +68,18 @@ static void update_handle_types_for_movement(int8_t &type, int8_t &other)
|
||||
}
|
||||
}
|
||||
|
||||
static void set_position_in_component(CurveComponent &component,
|
||||
static void set_position_in_component(bke::CurvesGeometry &curves,
|
||||
const GeometryNodeCurveHandleMode mode,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float3> &position_field,
|
||||
const Field<float3> &offset_field)
|
||||
{
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
if (domain_size == 0) {
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.points_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add(position_field);
|
||||
evaluator.add(offset_field);
|
||||
@@ -89,9 +88,6 @@ static void set_position_in_component(CurveComponent &component,
|
||||
const VArray<float3> new_positions = evaluator.get_evaluated<float3>(0);
|
||||
const VArray<float3> new_offsets = evaluator.get_evaluated<float3>(1);
|
||||
|
||||
Curves &curves_id = *component.get_for_write();
|
||||
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
Span<float3> positions = curves.positions();
|
||||
|
||||
const bool use_left = mode == GEO_NODE_CURVE_HANDLE_LEFT;
|
||||
@@ -141,22 +137,17 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
std::atomic<bool> has_bezier = false;
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_curves()) {
|
||||
return;
|
||||
}
|
||||
has_curves = true;
|
||||
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
|
||||
const AttributeAccessor attributes = *component.attributes();
|
||||
if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
|
||||
return;
|
||||
}
|
||||
has_bezier = true;
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
|
||||
has_curves = true;
|
||||
const AttributeAccessor attributes = curves.attributes();
|
||||
if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
|
||||
return;
|
||||
}
|
||||
has_bezier = true;
|
||||
|
||||
set_position_in_component(geometry_set.get_component_for_write<CurveComponent>(),
|
||||
mode,
|
||||
selection_field,
|
||||
position_field,
|
||||
offset_field);
|
||||
set_position_in_component(curves, mode, selection_field, position_field, offset_field);
|
||||
}
|
||||
});
|
||||
|
||||
if (has_curves && !has_bezier) {
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_curve_radius_cc {
|
||||
@@ -16,21 +18,19 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Curve"));
|
||||
}
|
||||
|
||||
static void set_radius_in_component(GeometryComponent &component,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float> &radius_field)
|
||||
static void set_radius(bke::CurvesGeometry &curves,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float> &radius_field)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
if (domain_size == 0) {
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
|
||||
MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
|
||||
ATTR_DOMAIN_POINT);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.points_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(radius_field, radii.varray);
|
||||
evaluator.evaluate();
|
||||
@@ -45,9 +45,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_curves()) {
|
||||
set_radius_in_component(
|
||||
geometry_set.get_component_for_write<CurveComponent>(), selection_field, radii_field);
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
set_radius(bke::CurvesGeometry::wrap(curves_id->geometry), selection_field, radii_field);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_curve_tilt_cc {
|
||||
@@ -12,22 +14,19 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Curve"));
|
||||
}
|
||||
|
||||
static void set_tilt_in_component(GeometryComponent &component,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float> &tilt_field)
|
||||
static void set_tilt(bke::CurvesGeometry &curves,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float> &tilt_field)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
if (domain_size == 0) {
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
|
||||
MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
AttributeWriter<float> tilts = attributes.lookup_or_add_for_write<float>("tilt",
|
||||
ATTR_DOMAIN_POINT);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.points_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(tilt_field, tilts.varray);
|
||||
evaluator.evaluate();
|
||||
@@ -42,9 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Field<float> tilt_field = params.extract_input<Field<float>>("Tilt");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_curves()) {
|
||||
set_tilt_in_component(
|
||||
geometry_set.get_component_for_write<CurveComponent>(), selection_field, tilt_field);
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
set_tilt(bke::CurvesGeometry::wrap(curves_id->geometry), selection_field, tilt_field);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -24,7 +24,7 @@ static void set_id_in_component(GeometryComponent &component,
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
GeometryComponentFieldContext field_context{component, domain};
|
||||
bke::GeometryFieldContext field_context{component, domain};
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
evaluator.set_selection(selection_field);
|
||||
|
@@ -72,8 +72,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (geometry_set.has_mesh()) {
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
Mesh &mesh = *mesh_component.get_for_write();
|
||||
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
|
||||
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
|
||||
fn::FieldEvaluator selection_evaluator{field_context, mesh.totpoly};
|
||||
selection_evaluator.add(selection_field);
|
||||
selection_evaluator.evaluate();
|
||||
|
@@ -14,17 +14,17 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
|
||||
static void set_material_index_in_component(GeometryComponent &component,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<int> &index_field)
|
||||
const Field<int> &index_field,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
||||
const int domain_size = component.attribute_domain_size(domain);
|
||||
if (domain_size == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
|
||||
bke::GeometryFieldContext field_context{component, domain};
|
||||
|
||||
AttributeWriter<int> indices = attributes.lookup_or_add_for_write<int>("material_index",
|
||||
ATTR_DOMAIN_FACE);
|
||||
AttributeWriter<int> indices = attributes.lookup_or_add_for_write<int>("material_index", domain);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
evaluator.set_selection(selection_field);
|
||||
@@ -41,8 +41,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_mesh()) {
|
||||
set_material_index_in_component(
|
||||
geometry_set.get_component_for_write<MeshComponent>(), selection_field, index_field);
|
||||
set_material_index_in_component(geometry_set.get_component_for_write<MeshComponent>(),
|
||||
selection_field,
|
||||
index_field,
|
||||
ATTR_DOMAIN_FACE);
|
||||
}
|
||||
});
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_point_radius_cc {
|
||||
@@ -16,21 +18,19 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Points"));
|
||||
}
|
||||
|
||||
static void set_radius_in_component(GeometryComponent &component,
|
||||
static void set_radius_in_component(PointCloud &pointcloud,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<float> &radius_field)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
if (domain_size == 0) {
|
||||
if (pointcloud.totpoint == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||
|
||||
MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
|
||||
AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
|
||||
ATTR_DOMAIN_POINT);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::PointCloudFieldContext field_context{pointcloud};
|
||||
fn::FieldEvaluator evaluator{field_context, pointcloud.totpoint};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(radius_field, radii.varray);
|
||||
evaluator.evaluate();
|
||||
@@ -45,10 +45,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_pointcloud()) {
|
||||
set_radius_in_component(geometry_set.get_component_for_write<PointCloudComponent>(),
|
||||
selection_field,
|
||||
radii_field);
|
||||
if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) {
|
||||
set_radius_in_component(*pointcloud, selection_field, radii_field);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -136,7 +136,7 @@ static void set_position_in_component(GeometryComponent &component,
|
||||
{
|
||||
eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE :
|
||||
ATTR_DOMAIN_POINT;
|
||||
GeometryComponentFieldContext field_context{component, domain};
|
||||
bke::GeometryFieldContext field_context{component, domain};
|
||||
const int domain_size = component.attribute_domain_size(domain);
|
||||
if (domain_size == 0) {
|
||||
return;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_shade_smooth_cc {
|
||||
@@ -12,27 +14,25 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Geometry"));
|
||||
}
|
||||
|
||||
static void set_smooth_in_component(GeometryComponent &component,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &shade_field)
|
||||
static void set_smooth(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &shade_field)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
||||
if (domain_size == 0) {
|
||||
if (mesh.totpoly == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
|
||||
|
||||
AttributeWriter<bool> shades = attributes.lookup_or_add_for_write<bool>("shade_smooth",
|
||||
MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
|
||||
AttributeWriter<bool> smooth = attributes.lookup_or_add_for_write<bool>("shade_smooth",
|
||||
ATTR_DOMAIN_FACE);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
|
||||
fn::FieldEvaluator evaluator{field_context, mesh.totpoly};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(shade_field, shades.varray);
|
||||
evaluator.add_with_destination(shade_field, smooth.varray);
|
||||
evaluator.evaluate();
|
||||
|
||||
shades.finish();
|
||||
smooth.finish();
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
@@ -42,9 +42,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Field<bool> shade_field = params.extract_input<Field<bool>>("Shade Smooth");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_mesh()) {
|
||||
set_smooth_in_component(
|
||||
geometry_set.get_component_for_write<MeshComponent>(), selection_field, shade_field);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
set_smooth(*mesh, selection_field, shade_field);
|
||||
}
|
||||
});
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_spline_cyclic_cc {
|
||||
@@ -12,22 +14,19 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Geometry"));
|
||||
}
|
||||
|
||||
static void set_cyclic_in_component(GeometryComponent &component,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &cyclic_field)
|
||||
static void set_cyclic(bke::CurvesGeometry &curves,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &cyclic_field)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
|
||||
if (domain_size == 0) {
|
||||
if (curves.curves_num() == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
|
||||
|
||||
MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
AttributeWriter<bool> cyclics = attributes.lookup_or_add_for_write<bool>("cyclic",
|
||||
ATTR_DOMAIN_CURVE);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(cyclic_field, cyclics.varray);
|
||||
evaluator.evaluate();
|
||||
@@ -42,9 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Field<bool> cyclic_field = params.extract_input<Field<bool>>("Cyclic");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_curves()) {
|
||||
set_cyclic_in_component(
|
||||
geometry_set.get_component_for_write<CurveComponent>(), selection_field, cyclic_field);
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
set_cyclic(bke::CurvesGeometry::wrap(curves_id->geometry), selection_field, cyclic_field);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_set_spline_resolution_cc {
|
||||
@@ -12,22 +14,19 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Geometry"));
|
||||
}
|
||||
|
||||
static void set_resolution_in_component(GeometryComponent &component,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<int> &resolution_field)
|
||||
static void set_resolution(bke::CurvesGeometry &curves,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<int> &resolution_field)
|
||||
{
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
|
||||
if (domain_size == 0) {
|
||||
if (curves.curves_num() == 0) {
|
||||
return;
|
||||
}
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
|
||||
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
|
||||
|
||||
MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
AttributeWriter<int> resolutions = attributes.lookup_or_add_for_write<int>("resolution",
|
||||
ATTR_DOMAIN_CURVE);
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||
bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(resolution_field, resolutions.varray);
|
||||
evaluator.evaluate();
|
||||
@@ -38,12 +37,13 @@ static void set_resolution_in_component(GeometryComponent &component,
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
Field<int> resolution_field = params.extract_input<Field<int>>("Resolution");
|
||||
Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
Field<int> resolution = params.extract_input<Field<int>>("Resolution");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
set_resolution_in_component(
|
||||
geometry_set.get_component_for_write<CurveComponent>(), selection_field, resolution_field);
|
||||
if (Curves *curves_id = geometry_set.get_curves_for_write()) {
|
||||
set_resolution(bke::CurvesGeometry::wrap(curves_id->geometry), selection, resolution);
|
||||
}
|
||||
});
|
||||
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
|
@@ -98,7 +98,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext field_context{component, domain};
|
||||
bke::GeometryFieldContext field_context{component, domain};
|
||||
const IndexMask mask{IndexMask(domain_size)};
|
||||
|
||||
const CPPType &type = field.cpp_type();
|
||||
|
@@ -119,21 +119,19 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
|
||||
if (verts_num == 0 || edges_num == 0) {
|
||||
const Mesh &mesh = *geometry_set.get_mesh_for_read();
|
||||
if (mesh.totvert == 0 || mesh.totedge == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext point_context{mesh_component, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator point_evaluator(point_context, verts_num);
|
||||
bke::MeshFieldContext point_context{mesh, ATTR_DOMAIN_POINT};
|
||||
FieldEvaluator point_evaluator(point_context, mesh.totvert);
|
||||
point_evaluator.add(vertex_crease_field);
|
||||
point_evaluator.evaluate();
|
||||
const VArray<float> vertex_creases = point_evaluator.get_evaluated<float>(0);
|
||||
|
||||
GeometryComponentFieldContext edge_context{mesh_component, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator edge_evaluator(edge_context, edges_num);
|
||||
bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator edge_evaluator(edge_context, mesh.totedge);
|
||||
edge_evaluator.add(edge_crease_field);
|
||||
edge_evaluator.evaluate();
|
||||
const VArray<float> edge_creases = edge_evaluator.get_evaluated<float>(0);
|
||||
@@ -162,17 +160,15 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
|
||||
uv_smooth);
|
||||
|
||||
const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
|
||||
|
||||
/* Apply subdivision to mesh. */
|
||||
Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh_in);
|
||||
Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh);
|
||||
|
||||
/* In case of bad topology, skip to input mesh. */
|
||||
if (subdiv == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh_in);
|
||||
Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh);
|
||||
|
||||
geometry_set.replace_mesh(mesh_out);
|
||||
|
||||
|
@@ -387,7 +387,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
|
||||
|
||||
fn::MFSignature signature_;
|
||||
|
||||
std::optional<GeometryComponentFieldContext> source_context_;
|
||||
std::optional<bke::MeshFieldContext> source_context_;
|
||||
std::unique_ptr<FieldEvaluator> source_evaluator_;
|
||||
const GVArray *source_data_;
|
||||
|
||||
@@ -431,10 +431,10 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
|
||||
private:
|
||||
void evaluate_source_field()
|
||||
{
|
||||
const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
|
||||
source_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
|
||||
const int domain_num = mesh_component.attribute_domain_size(domain_);
|
||||
source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_num);
|
||||
const Mesh &mesh = *source_.get_mesh_for_read();
|
||||
source_context_.emplace(bke::MeshFieldContext{mesh, domain_});
|
||||
const int domain_size = bke::mesh_attributes(mesh).domain_size(domain_);
|
||||
source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_size);
|
||||
source_evaluator_->add(src_field_);
|
||||
source_evaluator_->evaluate();
|
||||
source_data_ = &source_evaluator_->get_evaluated(0);
|
||||
@@ -457,11 +457,11 @@ class NearestTransferFunction : public fn::MultiFunction {
|
||||
bool use_points_;
|
||||
|
||||
/* Store data from the source as a virtual array, since we may only access a few indices. */
|
||||
std::optional<GeometryComponentFieldContext> mesh_context_;
|
||||
std::optional<bke::MeshFieldContext> mesh_context_;
|
||||
std::unique_ptr<FieldEvaluator> mesh_evaluator_;
|
||||
const GVArray *mesh_data_;
|
||||
|
||||
std::optional<GeometryComponentFieldContext> point_context_;
|
||||
std::optional<bke::PointCloudFieldContext> point_context_;
|
||||
std::unique_ptr<FieldEvaluator> point_evaluator_;
|
||||
const GVArray *point_data_;
|
||||
|
||||
@@ -577,20 +577,19 @@ class NearestTransferFunction : public fn::MultiFunction {
|
||||
void evaluate_source_field()
|
||||
{
|
||||
if (use_mesh_) {
|
||||
const MeshComponent &mesh = *source_.get_component_for_read<MeshComponent>();
|
||||
const int domain_num = mesh.attribute_domain_size(domain_);
|
||||
mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_));
|
||||
mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_num);
|
||||
const Mesh &mesh = *source_.get_mesh_for_read();
|
||||
const int domain_size = bke::mesh_attributes(mesh).domain_size(domain_);
|
||||
mesh_context_.emplace(bke::MeshFieldContext(mesh, domain_));
|
||||
mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_size);
|
||||
mesh_evaluator_->add(src_field_);
|
||||
mesh_evaluator_->evaluate();
|
||||
mesh_data_ = &mesh_evaluator_->get_evaluated(0);
|
||||
}
|
||||
|
||||
if (use_points_) {
|
||||
const PointCloudComponent &points = *source_.get_component_for_read<PointCloudComponent>();
|
||||
const int domain_num = points.attribute_domain_size(domain_);
|
||||
point_context_.emplace(GeometryComponentFieldContext(points, domain_));
|
||||
point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_num);
|
||||
const PointCloud &points = *source_.get_pointcloud_for_read();
|
||||
point_context_.emplace(bke::PointCloudFieldContext(points));
|
||||
point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, points.totpoint);
|
||||
point_evaluator_->add(src_field_);
|
||||
point_evaluator_->evaluate();
|
||||
point_data_ = &point_evaluator_->get_evaluated(0);
|
||||
@@ -628,7 +627,7 @@ class IndexTransferFunction : public fn::MultiFunction {
|
||||
|
||||
fn::MFSignature signature_;
|
||||
|
||||
std::optional<GeometryComponentFieldContext> geometry_context_;
|
||||
std::optional<bke::GeometryFieldContext> geometry_context_;
|
||||
std::unique_ptr<FieldEvaluator> evaluator_;
|
||||
const GVArray *src_data_ = nullptr;
|
||||
|
||||
@@ -659,7 +658,7 @@ class IndexTransferFunction : public fn::MultiFunction {
|
||||
return;
|
||||
}
|
||||
const int domain_num = component->attribute_domain_size(domain_);
|
||||
geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_));
|
||||
geometry_context_.emplace(bke::GeometryFieldContext(*component, domain_));
|
||||
evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_num);
|
||||
evaluator_->add(src_field_);
|
||||
evaluator_->evaluate();
|
||||
|
@@ -17,9 +17,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
|
||||
static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component)
|
||||
{
|
||||
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, instances_component.instances_num()};
|
||||
const bke::InstancesFieldContext context{instances_component};
|
||||
fn::FieldEvaluator evaluator{context, instances_component.instances_num()};
|
||||
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
|
||||
evaluator.add(params.extract_input<Field<float3>>("Translation"));
|
||||
evaluator.add(params.extract_input<Field<bool>>("Local Space"));
|
||||
|
@@ -77,12 +77,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (!geometry_set.has_mesh()) {
|
||||
return;
|
||||
}
|
||||
GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
|
||||
|
||||
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
||||
GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator evaluator{context, domain_size};
|
||||
bke::MeshFieldContext context{mesh_in, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator evaluator{context, mesh_in.totpoly};
|
||||
evaluator.add(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
|
@@ -28,21 +28,15 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Vector>(N_("UV")).field_source();
|
||||
}
|
||||
|
||||
static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
||||
const Field<bool> selection_field,
|
||||
const Field<float3> uv_field,
|
||||
const bool rotate,
|
||||
const float margin,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
||||
GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator face_evaluator{face_context, face_num};
|
||||
bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator face_evaluator{face_context, mesh.totpoly};
|
||||
face_evaluator.add(selection_field);
|
||||
face_evaluator.evaluate();
|
||||
const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
|
||||
@@ -50,25 +44,29 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
return {};
|
||||
}
|
||||
|
||||
const int corner_num = component.attribute_domain_size(ATTR_DOMAIN_CORNER);
|
||||
GeometryComponentFieldContext corner_context{component, ATTR_DOMAIN_CORNER};
|
||||
FieldEvaluator evaluator{corner_context, corner_num};
|
||||
Array<float3> uv(corner_num);
|
||||
bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER};
|
||||
FieldEvaluator evaluator{corner_context, mesh.totloop};
|
||||
Array<float3> uv(mesh.totloop);
|
||||
evaluator.add_with_destination(uv_field, uv.as_mutable_span());
|
||||
evaluator.evaluate();
|
||||
|
||||
const Span<MVert> vertices(mesh.mvert, mesh.totvert);
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
const Span<MPoly> polygons(mesh.mpoly, mesh.totpoly);
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
for (const int mp_index : selection) {
|
||||
const MPoly &mp = mesh->mpoly[mp_index];
|
||||
const MPoly &mp = polygons[mp_index];
|
||||
Array<ParamKey, 16> mp_vkeys(mp.totloop);
|
||||
Array<bool, 16> mp_pin(mp.totloop);
|
||||
Array<bool, 16> mp_select(mp.totloop);
|
||||
Array<const float *, 16> mp_co(mp.totloop);
|
||||
Array<float *, 16> mp_uv(mp.totloop);
|
||||
for (const int i : IndexRange(mp.totloop)) {
|
||||
const MLoop &ml = mesh->mloop[mp.loopstart + i];
|
||||
const MLoop &ml = loops[mp.loopstart + i];
|
||||
mp_vkeys[i] = ml.v;
|
||||
mp_co[i] = mesh->mvert[ml.v].co;
|
||||
mp_co[i] = vertices[ml.v].co;
|
||||
mp_uv[i] = uv[mp.loopstart + i];
|
||||
mp_pin[i] = false;
|
||||
mp_select[i] = false;
|
||||
@@ -88,11 +86,11 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
GEO_uv_parametrizer_flush(handle);
|
||||
GEO_uv_parametrizer_delete(handle);
|
||||
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
|
||||
}
|
||||
|
||||
class PackIslandsFieldInput final : public GeometryFieldInput {
|
||||
class PackIslandsFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
const Field<bool> selection_field;
|
||||
const Field<float3> uv_field;
|
||||
@@ -104,7 +102,7 @@ class PackIslandsFieldInput final : public GeometryFieldInput {
|
||||
const Field<float3> uv_field,
|
||||
const bool rotate,
|
||||
const float margin)
|
||||
: GeometryFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
|
||||
: bke::MeshFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
|
||||
selection_field(selection_field),
|
||||
uv_field(uv_field),
|
||||
rotate(rotate),
|
||||
@@ -113,16 +111,11 @@ class PackIslandsFieldInput final : public GeometryFieldInput {
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_uv_gvarray(
|
||||
mesh_component, selection_field, uv_field, rotate, margin, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_uv_gvarray(mesh, selection_field, uv_field, rotate, margin, domain);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -52,7 +52,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
||||
const Field<bool> selection_field,
|
||||
const Field<bool> seam_field,
|
||||
const bool fill_holes,
|
||||
@@ -60,14 +60,8 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
const GeometryNodeUVUnwrapMethod method,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
const Mesh *mesh = component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
||||
GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator face_evaluator{face_context, face_num};
|
||||
bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
|
||||
FieldEvaluator face_evaluator{face_context, mesh.totpoly};
|
||||
face_evaluator.add(selection_field);
|
||||
face_evaluator.evaluate();
|
||||
const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
|
||||
@@ -75,27 +69,31 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
return {};
|
||||
}
|
||||
|
||||
const int edge_num = component.attribute_domain_size(ATTR_DOMAIN_EDGE);
|
||||
GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator edge_evaluator{edge_context, edge_num};
|
||||
bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
|
||||
FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
|
||||
edge_evaluator.add(seam_field);
|
||||
edge_evaluator.evaluate();
|
||||
const IndexMask seam = edge_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
Array<float3> uv(mesh->totloop, float3(0));
|
||||
const Span<MVert> vertices(mesh.mvert, mesh.totvert);
|
||||
const Span<MEdge> edges(mesh.medge, mesh.totedge);
|
||||
const Span<MPoly> polygons(mesh.mpoly, mesh.totpoly);
|
||||
const Span<MLoop> loops(mesh.mloop, mesh.totloop);
|
||||
|
||||
Array<float3> uv(loops.size(), float3(0));
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
for (const int mp_index : selection) {
|
||||
const MPoly &mp = mesh->mpoly[mp_index];
|
||||
const MPoly &mp = polygons[mp_index];
|
||||
Array<ParamKey, 16> mp_vkeys(mp.totloop);
|
||||
Array<bool, 16> mp_pin(mp.totloop);
|
||||
Array<bool, 16> mp_select(mp.totloop);
|
||||
Array<const float *, 16> mp_co(mp.totloop);
|
||||
Array<float *, 16> mp_uv(mp.totloop);
|
||||
for (const int i : IndexRange(mp.totloop)) {
|
||||
const MLoop &ml = mesh->mloop[mp.loopstart + i];
|
||||
const MLoop &ml = loops[mp.loopstart + i];
|
||||
mp_vkeys[i] = ml.v;
|
||||
mp_co[i] = mesh->mvert[ml.v].co;
|
||||
mp_co[i] = vertices[ml.v].co;
|
||||
mp_uv[i] = uv[mp.loopstart + i];
|
||||
mp_pin[i] = false;
|
||||
mp_select[i] = false;
|
||||
@@ -110,7 +108,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
mp_select.data());
|
||||
}
|
||||
for (const int i : seam) {
|
||||
const MEdge &edge = mesh->medge[i];
|
||||
const MEdge &edge = edges[i];
|
||||
ParamKey vkeys[2]{edge.v1, edge.v2};
|
||||
GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
}
|
||||
@@ -126,11 +124,11 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
|
||||
GEO_uv_parametrizer_flush(handle);
|
||||
GEO_uv_parametrizer_delete(handle);
|
||||
|
||||
return component.attributes()->adapt_domain<float3>(
|
||||
return bke::mesh_attributes(mesh).adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
|
||||
}
|
||||
|
||||
class UnwrapFieldInput final : public GeometryFieldInput {
|
||||
class UnwrapFieldInput final : public bke::MeshFieldInput {
|
||||
private:
|
||||
const Field<bool> selection;
|
||||
const Field<bool> seam;
|
||||
@@ -144,7 +142,7 @@ class UnwrapFieldInput final : public GeometryFieldInput {
|
||||
const bool fill_holes,
|
||||
const float margin,
|
||||
const GeometryNodeUVUnwrapMethod method)
|
||||
: GeometryFieldInput(CPPType::get<float3>(), "UV Unwrap Field"),
|
||||
: bke::MeshFieldInput(CPPType::get<float3>(), "UV Unwrap Field"),
|
||||
selection(selection),
|
||||
seam(seam),
|
||||
fill_holes(fill_holes),
|
||||
@@ -154,16 +152,11 @@ class UnwrapFieldInput final : public GeometryFieldInput {
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
|
||||
GVArray get_varray_for_context(const GeometryComponent &component,
|
||||
GVArray get_varray_for_context(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
IndexMask UNUSED(mask)) const final
|
||||
{
|
||||
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
return construct_uv_gvarray(
|
||||
mesh_component, selection, seam, fill_holes, margin, method, domain);
|
||||
}
|
||||
return {};
|
||||
return construct_uv_gvarray(mesh, selection, seam, fill_holes, margin, method, domain);
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user