22#include <fmt/format.h>
27 : mesh_(mesh), domain_(domain)
29 BLI_assert(mesh.attributes().domain_supported(domain_));
33 : curves_(curves), domain_(domain)
35 BLI_assert(curves.attributes().domain_supported(domain));
54 if (drawing->strokes().attributes().domain_supported(this->domain())) {
56 return curves_field_input->get_varray_for_context(context, mask, scope);
66 : geometry_(other.geometry_),
69 curves_id_(other.curves_id_),
70 grease_pencil_layer_index_(other.grease_pencil_layer_index_)
77 const int grease_pencil_layer_index)
78 : geometry_(geometry),
81 grease_pencil_layer_index_(grease_pencil_layer_index)
93 : type_(component.type()), domain_(domain)
95 switch (component.
type()) {
98 geometry_ = mesh_component.
get();
103 const Curves *curves = curve_component.
get();
104 geometry_ = curves ? &curves->geometry.wrap() :
nullptr;
105 curves_id_ = curve_component.
get();
111 geometry_ = pointcloud_component.
get();
117 geometry_ = grease_pencil_component.
get();
125 geometry_ = instances_component.
get();
144 : geometry_(&curves_id.geometry.
wrap()),
147 curves_id_(&curves_id)
155 : geometry_(&grease_pencil),
162 const int layer_index)
163 : geometry_(&grease_pencil),
166 grease_pencil_layer_index_(layer_index)
170 : geometry_(&instances),
178 if (
const Mesh *mesh = this->
mesh()) {
179 return mesh->attributes();
182 return curves->attributes();
194 return drawing->strokes().attributes();
198 return instances->attributes();
234 this->
grease_pencil()->layer(this->grease_pencil_layer_index_));
242 return &drawing->strokes();
253 static_cast<const Instances *
>(geometry_) :
271 if (
const Curves *curves_id = curve_context->curves_id()) {
290 grease_pencil_context->domain(),
291 grease_pencil_context->layer_index()},
315 if (
const Mesh *mesh = geometry_context->mesh()) {
337 if (
const CurvesGeometry *curves = geometry_context->curves_or_strokes()) {
362 if (
const PointCloud *pointcloud = geometry_context->pointcloud()) {
381 if (
const Instances *instances = geometry_context->instances()) {
398 if (
const GreasePencil *grease_pencil = context.grease_pencil()) {
401 return *layer_attributes.
lookup(name_, data_type);
404 const int layer_index = context.grease_pencil_layer_index();
414 reader.varray.get_to_uninitialized(layer_index, value);
415 const int domain_size = curves_attributes.
domain_size(domain);
424 else if (
auto attributes = context.attributes()) {
425 return *attributes->lookup(name_, domain, data_type);
436 const AttributeAccessor layer_attributes = context.grease_pencil()->attributes();
438 const bool exists = layer_attributes.
contains(name_);
444 const bool exists = layer_attributes.
contains(name_) || curve_attributes.
contains(name_);
445 const int domain_size = curve_attributes.
domain_size(domain);
448 const bool exists = context.attributes()->contains(name_);
449 const int domain_size = context.attributes()->domain_size(domain);
455 if (socket_inspection_name_) {
456 return *socket_inspection_name_;
458 return fmt::format(
TIP_(
"\"{}\" attribute from geometry"), name_);
469 return name_ == other_typed->name_ &&
type_ == other_typed->type_;
477 const std::optional<AttributeAccessor> attributes = component.
attributes();
478 if (!attributes.has_value()) {
481 const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data(name_);
482 if (!meta_data.has_value()) {
485 return meta_data->domain;
504 if (
auto attributes = context.attributes()) {
516 return TIP_(
"ID / Index");
534 using namespace bke::greasepencil;
540 const GreasePencil &grease_pencil = *context.grease_pencil();
541 if (!context.grease_pencil()) {
545 auto layer_is_selected = [selection_name =
StringRef(layer_name_),
547 size = mask.min_array_size()](
const int layer_i) {
548 if (layer_i < 0 || layer_i >= grease_pencil.layers().size()) {
551 const Layer &layer = grease_pencil.layer(layer_i);
552 return layer.name() == selection_name;
556 const int layer_i = context.grease_pencil_layer_index();
557 const bool selected = layer_is_selected(layer_i);
574 return layer_name_ == other_named_layer->layer_name_;
593 mask.foreach_index(
GrainSize(4096), [&](
const int i) {
594 const int index = indices[i];
611 using T = decltype(dummy);
612 copy_with_checked_indices(src.typed<T>(), indices, mask, dst.typed<T>());
620 index_field_(std::move(index_field)),
621 value_field_(std::move(value_field)),
622 value_field_domain_(value_field_domain)
629 const std::optional<AttributeAccessor> attributes = context.attributes();
635 fn::FieldEvaluator value_evaluator{value_context, attributes->domain_size(value_field_domain_)};
636 value_evaluator.
add(value_field_);
637 value_evaluator.evaluate();
638 const GVArray &values = value_evaluator.get_evaluated(0);
641 index_evaluator.
add(index_field_);
642 index_evaluator.evaluate();
643 const VArray<int> indices = index_evaluator.get_evaluated<
int>(0);
645 GArray<> dst_array(values.type(), mask.min_array_size());
652 src_field_(std::move(field)),
660 const AttrDomain dst_domain = context.domain();
661 const int dst_domain_size = context.attributes()->domain_size(dst_domain);
674 value_evaluator.add(src_field_);
675 value_evaluator.evaluate();
677 const GVArray &values = value_evaluator.get_evaluated(0);
681 values.get_to_uninitialized(layer_index, value);
691 const int64_t src_domain_size = attributes.domain_size(src_domain_);
695 value_evaluator.evaluate();
696 return attributes.adapt_domain(
GVArray::ForGArray(std::move(values)), src_domain_, dst_domain);
722 if (
const Mesh *mesh = context.mesh()) {
733 return TIP_(
"Normal");
749 return field->attribute_name();
774 const std::optional<AttributeMetaData> meta_data = attributes.lookup_meta_data(*field_id);
783 const GAttributeReader attribute = attributes.lookup(*field_id, domain, data_type);
784 if (!attribute.sharing_info || !attribute.varray.is_span()) {
788 *attribute.sharing_info);
789 return attributes.add(id_to_create, domain, data_type,
init);
802 return varray_info.
data == attribute_info.
data;
813 const int domain_size = attributes.domain_size(domain);
814 if (domain_size == 0) {
815 bool all_added =
true;
824 evaluator.set_selection(selection);
826 const bool selection_is_full = !selection.node().depends_on_input() &&
842 for (
const int input_index : attribute_ids.
index_range()) {
843 const StringRef id = attribute_ids[input_index];
846 const CPPType &type = field.cpp_type();
850 if (dst.domain == domain && dst.varray.type() == field.cpp_type()) {
851 const int evaluator_index = evaluator.add(field);
852 results_to_store.
append({input_index, evaluator_index});
857 if (!validator && selection_is_full) {
866 if (!selection_is_full) {
867 type.value_initialize_n(buffer, domain_size);
871 const int evaluator_index = evaluator.add_with_destination(field, dst);
872 results_to_add.
append({input_index, evaluator_index, buffer});
875 evaluator.evaluate();
876 const IndexMask &mask = evaluator.get_evaluated_selection_as_mask();
878 for (
const StoreResult &result : results_to_store) {
879 const StringRef id = attribute_ids[result.input_index];
880 const GVArray &result_data = evaluator.get_evaluated(result.evaluator_index);
890 for (
const AddResult &result : results_to_add) {
891 const StringRef id = attribute_ids[result.input_index];
892 attributes.remove(
id);
893 const CPPType &type = fields[result.input_index].cpp_type();
898 type.destruct_n(result.buffer, domain_size);
919 GreasePencil *grease_pencil = grease_pencil_component.get_for_write();
920 if (grease_pencil ==
nullptr) {
923 bool any_success =
false;
925 for (const int layer_index : range) {
926 if (greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing(
927 grease_pencil->layer(layer_index)))
929 const GeometryFieldContext field_context{*grease_pencil, domain, layer_index};
930 const bool success = try_capture_fields_on_geometry(
931 drawing->strokes_for_write().attributes_for_write(),
937 if (success & !any_success) {
950 MutableAttributeAccessor attributes = *component.attributes_for_write();
951 const GeometryFieldContext field_context{component, domain};
953 attributes, field_context, attribute_ids, domain, selection, fields);
969 if (component_type == GeometryComponent::Type::PointCloud) {
970 return AttrDomain::Point;
972 if (component_type == GeometryComponent::Type::GreasePencil) {
973 return AttrDomain::Layer;
975 if (component_type == GeometryComponent::Type::Instance) {
976 return AttrDomain::Instance;
978 const std::shared_ptr<const fn::FieldInputs> &field_inputs = field.node().field_inputs();
982 std::optional<AttrDomain> output_domain;
983 auto handle_domain = [&](
const std::optional<AttrDomain> domain) {
984 if (!domain.has_value()) {
987 if (output_domain.has_value()) {
988 if (*output_domain != *domain) {
993 output_domain = domain;
996 if (component_type == GeometryComponent::Type::Mesh) {
998 const Mesh *mesh = mesh_component.
get();
999 if (mesh ==
nullptr) {
1000 return std::nullopt;
1002 for (
const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) {
1006 if (!handle_domain(geometry_field_input->preferred_domain(component))) {
1007 return std::nullopt;
1010 else if (
const auto *mesh_field_input =
dynamic_cast<const MeshFieldInput *
>(&field_input)) {
1011 if (!handle_domain(mesh_field_input->preferred_domain(*mesh))) {
1012 return std::nullopt;
1016 return std::nullopt;
1020 if (component_type == GeometryComponent::Type::Curve) {
1022 const Curves *curves = curve_component.
get();
1023 if (curves ==
nullptr) {
1024 return std::nullopt;
1026 for (
const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) {
1030 if (!handle_domain(geometry_field_input->preferred_domain(component))) {
1031 return std::nullopt;
1034 else if (
const auto *curves_field_input =
dynamic_cast<const CurvesFieldInput *
>(
1037 if (!handle_domain(curves_field_input->preferred_domain(curves->geometry.wrap()))) {
1038 return std::nullopt;
1042 return std::nullopt;
1046 return output_domain;
Low-level operations for curves.
Low-level operations for grease pencil.
General operations for point clouds.
#define BLI_assert_unreachable()
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define BLI_SCOPED_DEFER(function_to_defer)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
void destruct(void *ptr) const
CommonVArrayInfo common_info() const
const CPPType & type() const
static GVArray ForGArray(GArray<> array)
static GVArray ForSingleDefault(const CPPType &type, int64_t size)
static GVArray ForSingle(const CPPType &type, int64_t size, const void *value)
constexpr bool contains(int64_t value) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
IndexRange index_range() const
static VArray ForSingle(T value, const int64_t size)
static VArray ForFunc(const int64_t size, GetFunc get_func)
void append(const T &value)
GAttributeReader lookup(const StringRef attribute_id) const
int domain_size(const AttrDomain domain) const
bool contains(const StringRef attribute_id) const
const Curves * get() const
const Curves * curves_id() const
CurvesFieldContext(const CurvesGeometry &curves, AttrDomain domain)
AttributeAccessor attributes() const
std::optional< AttrDomain > preferred_domain(const GeometryComponent &) const override
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
EvaluateOnDomainInput(fn::GField field, AttrDomain domain)
GVArray get_varray_for_context(const bke::GeometryFieldContext &context, const IndexMask &) const final
virtual std::optional< AttributeAccessor > attributes() const
const CurvesGeometry * curves() const
std::optional< AttributeAccessor > attributes() const
const Mesh * mesh() const
int grease_pencil_layer_index() const
const Instances * instances() const
const PointCloud * pointcloud() const
GeometryFieldContext(const GeometryFieldContext &other, AttrDomain domain)
const greasepencil::Drawing * grease_pencil_layer_drawing() const
const GreasePencil * grease_pencil() const
const CurvesGeometry * curves_or_strokes() const
GeometryComponent::Type type() const
const Curves * curves_id() const
const GreasePencil * get() const
const GreasePencil & grease_pencil() const
GVArray get_varray_for_input(const fn::FieldInput &field_input, const IndexMask &mask, ResourceScope &scope) const
AttrDomain domain() const
const Instances * get() const
MeshFieldContext(const Mesh &mesh, AttrDomain domain)
const PointCloud * get() const
const bke::CurvesGeometry & strokes() const
int add(GField field, GVArray *varray_ptr)
int add_with_destination(GField field, GVMutableArray dst)
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
const CPPType & cpp_type() const
const FieldNode & node() const
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
void MEM_freeN(void *vmemh)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
static bool attribute_kind_matches(const AttributeMetaData meta_data, const AttrDomain domain, const eCustomDataType data_type)
static bool attribute_data_matches_varray(const GAttributeReader &attribute, const GVArray &varray)
std::optional< AttrDomain > try_detect_field_domain(const GeometryComponent &component, const fn::GField &field)
void copy_with_checked_indices(const GVArray &src, const VArray< int > &indices, const IndexMask &mask, GMutableSpan dst)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
VArray< float3 > curve_normals_varray(const CurvesGeometry &curves, AttrDomain domain)
static std::optional< StringRefNull > try_get_field_direct_attribute_id(const fn::GField &any_field)
VArray< float3 > instance_position_varray(const Instances &instances)
static bool try_add_shared_field_attribute(MutableAttributeAccessor attributes, const StringRef id_to_create, const AttrDomain domain, const fn::GField &field)
VArray< float3 > mesh_normals_varray(const Mesh &mesh, const IndexMask &mask, AttrDomain domain)
static StringRef get_random_id_attribute_name(const AttrDomain domain)
bool try_capture_fields_on_geometry(MutableAttributeAccessor attributes, const fn::FieldContext &field_context, Span< StringRef > attribute_ids, AttrDomain domain, const fn::Field< bool > &selection, Span< fn::GField > fields)
GField make_constant_field(const CPPType &type, const void *value)
void evaluate_constant_field(const GField &field, void *r_value)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
void devirtualize_varray2(const VArray< T1 > &varray1, const VArray< T2 > &varray2, const Func &func, bool enable=true)
uint64_t get_default_hash(const T &v)
float wrap(float value, float max, float min)
unsigned __int64 uint64_t
fn::GField validate_field_if_necessary(const fn::GField &field) const