Compare commits
3 Commits
blender-v3
...
temp-geome
Author | SHA1 | Date | |
---|---|---|---|
781e400d40 | |||
2460b0d5a1 | |||
6525f47afa |
@@ -104,6 +104,7 @@ using blender::Span;
|
|||||||
using blender::Stack;
|
using blender::Stack;
|
||||||
using blender::Vector;
|
using blender::Vector;
|
||||||
using blender::VectorSet;
|
using blender::VectorSet;
|
||||||
|
using blender::nodes::FieldInferencingInterface;
|
||||||
using blender::nodes::InputSocketFieldType;
|
using blender::nodes::InputSocketFieldType;
|
||||||
using blender::nodes::NodeDeclaration;
|
using blender::nodes::NodeDeclaration;
|
||||||
using blender::nodes::OutputFieldDependency;
|
using blender::nodes::OutputFieldDependency;
|
||||||
@@ -132,6 +133,9 @@ static FieldInferencingInterface *node_field_inferencing_interface_copy(
|
|||||||
const FieldInferencingInterface &field_inferencing_interface);
|
const FieldInferencingInterface &field_inferencing_interface);
|
||||||
static void node_field_inferencing_interface_free(
|
static void node_field_inferencing_interface_free(
|
||||||
const FieldInferencingInterface *field_inferencing_interface);
|
const FieldInferencingInterface *field_inferencing_interface);
|
||||||
|
// namespace blender::bke::node_tree_inferencing {
|
||||||
|
// bool update_field_inferencing(bNodeTree &btree);
|
||||||
|
// }
|
||||||
|
|
||||||
static void ntree_init_data(ID *id)
|
static void ntree_init_data(ID *id)
|
||||||
{
|
{
|
||||||
@@ -677,6 +681,10 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
|
|||||||
ntree->execdata = nullptr;
|
ntree->execdata = nullptr;
|
||||||
|
|
||||||
ntree->field_inferencing_interface = nullptr;
|
ntree->field_inferencing_interface = nullptr;
|
||||||
|
if (ntree->type == NTREE_GEOMETRY) {
|
||||||
|
ntree->update |= (NTREE_UPDATE | NTREE_UPDATE_FIELD_INFERENCING);
|
||||||
|
// blender::bke::node_field_inferencing::update_field_inferencing(*ntree);
|
||||||
|
}
|
||||||
|
|
||||||
BLO_read_data_address(reader, &ntree->adt);
|
BLO_read_data_address(reader, &ntree->adt);
|
||||||
BKE_animdata_blend_read_data(reader, ntree->adt);
|
BKE_animdata_blend_read_data(reader, ntree->adt);
|
||||||
@@ -4456,24 +4464,6 @@ void ntreeUpdateAllNew(Main *main)
|
|||||||
FOREACH_NODETREE_END;
|
FOREACH_NODETREE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Information about how a node interacts with fields.
|
|
||||||
*/
|
|
||||||
struct FieldInferencingInterface {
|
|
||||||
Vector<InputSocketFieldType> inputs;
|
|
||||||
Vector<OutputFieldDependency> outputs;
|
|
||||||
|
|
||||||
friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
|
|
||||||
{
|
|
||||||
return a.inputs == b.inputs && a.outputs == b.outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static FieldInferencingInterface *node_field_inferencing_interface_copy(
|
static FieldInferencingInterface *node_field_inferencing_interface_copy(
|
||||||
const FieldInferencingInterface &field_inferencing_interface)
|
const FieldInferencingInterface &field_inferencing_interface)
|
||||||
{
|
{
|
||||||
|
@@ -1482,7 +1482,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deprecate the random float node in favor of the random float node. */
|
/* Deprecate the random float node in favor of the random value node. */
|
||||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||||
if (ntree->type != NTREE_GEOMETRY) {
|
if (ntree->type != NTREE_GEOMETRY) {
|
||||||
continue;
|
continue;
|
||||||
|
@@ -460,7 +460,15 @@ typedef struct bNodeLink {
|
|||||||
#define NTREE_CHUNKSIZE_512 512
|
#define NTREE_CHUNKSIZE_512 512
|
||||||
#define NTREE_CHUNKSIZE_1024 1024
|
#define NTREE_CHUNKSIZE_1024 1024
|
||||||
|
|
||||||
|
/** Workaround to forward-declare C++ type in C header. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace blender::nodes {
|
||||||
struct FieldInferencingInterface;
|
struct FieldInferencingInterface;
|
||||||
|
}
|
||||||
|
using FieldInferencingInterfaceHandle = blender::nodes::FieldInferencingInterface;
|
||||||
|
#else
|
||||||
|
typedef struct FieldInferencingInterfaceHandle FieldInferencingInterfaceHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* the basis for a Node tree, all links and nodes reside internal here */
|
/* the basis for a Node tree, all links and nodes reside internal here */
|
||||||
/* only re-usable node trees are in the library though,
|
/* only re-usable node trees are in the library though,
|
||||||
@@ -485,7 +493,7 @@ typedef struct bNodeTree {
|
|||||||
|
|
||||||
ListBase nodes, links;
|
ListBase nodes, links;
|
||||||
/** Information about how inputs and outputs of the node group interact with fields. */
|
/** Information about how inputs and outputs of the node group interact with fields. */
|
||||||
struct FieldInferencingInterface *field_inferencing_interface;
|
FieldInferencingInterfaceHandle *field_inferencing_interface;
|
||||||
|
|
||||||
/** Set init on fileread. */
|
/** Set init on fileread. */
|
||||||
int type, init;
|
int type, init;
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BLI_array.hh"
|
||||||
#include "BLI_float3.hh"
|
#include "BLI_float3.hh"
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_multi_value_map.hh"
|
#include "BLI_multi_value_map.hh"
|
||||||
@@ -88,10 +89,12 @@
|
|||||||
#include "NOD_derived_node_tree.hh"
|
#include "NOD_derived_node_tree.hh"
|
||||||
#include "NOD_geometry.h"
|
#include "NOD_geometry.h"
|
||||||
#include "NOD_geometry_nodes_eval_log.hh"
|
#include "NOD_geometry_nodes_eval_log.hh"
|
||||||
|
#include "NOD_node_declaration.hh"
|
||||||
|
|
||||||
#include "FN_field.hh"
|
#include "FN_field.hh"
|
||||||
#include "FN_multi_function.hh"
|
#include "FN_multi_function.hh"
|
||||||
|
|
||||||
|
using blender::Array;
|
||||||
using blender::ColorGeometry4f;
|
using blender::ColorGeometry4f;
|
||||||
using blender::destruct_ptr;
|
using blender::destruct_ptr;
|
||||||
using blender::float3;
|
using blender::float3;
|
||||||
@@ -105,7 +108,11 @@ using blender::StringRefNull;
|
|||||||
using blender::Vector;
|
using blender::Vector;
|
||||||
using blender::fn::GMutablePointer;
|
using blender::fn::GMutablePointer;
|
||||||
using blender::fn::GPointer;
|
using blender::fn::GPointer;
|
||||||
|
using blender::nodes::FieldInferencingInterface;
|
||||||
using blender::nodes::GeoNodeExecParams;
|
using blender::nodes::GeoNodeExecParams;
|
||||||
|
using blender::nodes::InputSocketFieldType;
|
||||||
|
using blender::nodes::OutputFieldDependency;
|
||||||
|
using blender::nodes::OutputSocketFieldType;
|
||||||
using blender::threading::EnumerableThreadSpecific;
|
using blender::threading::EnumerableThreadSpecific;
|
||||||
using namespace blender::fn::multi_function_types;
|
using namespace blender::fn::multi_function_types;
|
||||||
using namespace blender::nodes::derived_node_tree_types;
|
using namespace blender::nodes::derived_node_tree_types;
|
||||||
@@ -298,12 +305,44 @@ static bool logging_enabled(const ModifierEvalContext *ctx)
|
|||||||
static const std::string use_attribute_suffix = "_use_attribute";
|
static const std::string use_attribute_suffix = "_use_attribute";
|
||||||
static const std::string attribute_name_suffix = "_attribute_name";
|
static const std::string attribute_name_suffix = "_attribute_name";
|
||||||
|
|
||||||
|
/* TODO: Use a better check for this. */
|
||||||
|
static bool socket_type_can_be_attribute(const bNodeSocket &socket)
|
||||||
|
{
|
||||||
|
return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \return Whether using an attribute to input values of this type is supported.
|
* \return Whether using an attribute to input values of this type is supported.
|
||||||
*/
|
*/
|
||||||
static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
|
static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
|
||||||
{
|
{
|
||||||
return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT);
|
if (node_tree.field_inferencing_interface == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BLI_assert(node_tree.field_inferencing_interface != nullptr);
|
||||||
|
const FieldInferencingInterface &field_interface = *node_tree.field_inferencing_interface;
|
||||||
|
return field_interface.inputs[socket_index] != InputSocketFieldType::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Array<bool> inputs_use_attribute(const bNodeTree &node_tree, const NodesModifierData &nmd)
|
||||||
|
{
|
||||||
|
Vector<bNodeSocket *> inputs = node_tree.inputs;
|
||||||
|
Array<bool> result(inputs.size(), false);
|
||||||
|
for (const int i : inputs.index_range()) {
|
||||||
|
if (!input_has_attribute_toggle(node_tree, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const std::string use_attribute_prop_name = inputs[i]->identifier + use_attribute_suffix;
|
||||||
|
const IDProperty *use_attribute_prop = IDP_GetPropertyFromGroup(
|
||||||
|
nmd.settings.properties, use_attribute_prop_name.c_str());
|
||||||
|
if (use_attribute_prop == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (IDP_Int(use_attribute_prop) != 0) {
|
||||||
|
result[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
|
static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
|
||||||
@@ -531,7 +570,8 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|||||||
nmd->settings.properties = IDP_New(IDP_GROUP, &idprop, "Nodes Modifier Settings");
|
nmd->settings.properties = IDP_New(IDP_GROUP, &idprop, "Nodes Modifier Settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
|
int socket_index;
|
||||||
|
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
|
||||||
IDProperty *new_prop = id_property_create_from_socket(*socket);
|
IDProperty *new_prop = id_property_create_from_socket(*socket);
|
||||||
if (new_prop == nullptr) {
|
if (new_prop == nullptr) {
|
||||||
/* Out of the set of supported input sockets, only
|
/* Out of the set of supported input sockets, only
|
||||||
@@ -562,7 +602,7 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket_type_has_attribute_toggle(*socket)) {
|
if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
|
||||||
const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
|
const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
|
||||||
const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
|
const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
|
||||||
|
|
||||||
@@ -624,37 +664,38 @@ void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void initialize_group_input(NodesModifierData &nmd,
|
static void initialize_group_input(NodesModifierData &nmd,
|
||||||
const bNodeSocket &socket,
|
const OutputSocketRef &socket,
|
||||||
void *r_value)
|
void *r_value)
|
||||||
{
|
{
|
||||||
|
const bNodeSocket &bsocket = *socket.bsocket();
|
||||||
if (nmd.settings.properties == nullptr) {
|
if (nmd.settings.properties == nullptr) {
|
||||||
socket.typeinfo->get_geometry_nodes_cpp_value(socket, r_value);
|
socket.typeinfo()->get_geometry_nodes_cpp_value(bsocket, r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
|
const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
|
||||||
socket.identifier);
|
socket.identifier().c_str());
|
||||||
if (property == nullptr) {
|
if (property == nullptr) {
|
||||||
socket.typeinfo->get_geometry_nodes_cpp_value(socket, r_value);
|
socket.typeinfo()->get_geometry_nodes_cpp_value(bsocket, r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!id_property_type_matches_socket(socket, *property)) {
|
if (!id_property_type_matches_socket(bsocket, *property)) {
|
||||||
socket.typeinfo->get_geometry_nodes_cpp_value(socket, r_value);
|
socket.typeinfo()->get_geometry_nodes_cpp_value(bsocket, r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!socket_type_has_attribute_toggle(socket)) {
|
if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) {
|
||||||
init_socket_cpp_value_from_property(
|
init_socket_cpp_value_from_property(
|
||||||
*property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
|
*property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
|
const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
|
||||||
nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str());
|
nmd.settings.properties, (socket.identifier() + use_attribute_suffix).c_str());
|
||||||
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
|
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
|
||||||
nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str());
|
nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str());
|
||||||
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
|
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
|
||||||
init_socket_cpp_value_from_property(
|
init_socket_cpp_value_from_property(
|
||||||
*property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
|
*property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,12 +703,12 @@ static void initialize_group_input(NodesModifierData &nmd,
|
|||||||
if (use_attribute) {
|
if (use_attribute) {
|
||||||
const StringRef attribute_name{IDP_String(property_attribute_name)};
|
const StringRef attribute_name{IDP_String(property_attribute_name)};
|
||||||
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
|
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
|
||||||
attribute_name, *socket.typeinfo->get_base_cpp_type());
|
attribute_name, *socket.typeinfo()->get_base_cpp_type());
|
||||||
new (r_value) blender::fn::GField(std::move(attribute_input), 0);
|
new (r_value) blender::fn::GField(std::move(attribute_input), 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
init_socket_cpp_value_from_property(
|
init_socket_cpp_value_from_property(
|
||||||
*property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
|
*property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,14 +819,44 @@ static void clear_runtime_data(NodesModifierData *nmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Somehow choose which domain to use. */
|
||||||
|
static void evalaute_attributes_on_result_component(GeometryComponent &component,
|
||||||
|
Span<GMutablePointer> attribute_outputs)
|
||||||
|
{
|
||||||
|
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
|
||||||
|
const int domain_size = component.attribute_domain_size(domain);
|
||||||
|
const IndexMask mask{IndexMask(domain_size)};
|
||||||
|
|
||||||
|
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
|
||||||
|
OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
|
||||||
|
attribute_id, domain, data_type);
|
||||||
|
|
||||||
|
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||||
|
evaluator.add_with_destination(field, output_attribute.varray());
|
||||||
|
evaluator.evaluate();
|
||||||
|
|
||||||
|
output_attribute.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void evaluate_attributes_on_result_geometry(GeometrySet &geometry_set,
|
||||||
|
Span<GMutablePointer> attribute_outputs)
|
||||||
|
{
|
||||||
|
for (const GeometryComponentType type :
|
||||||
|
{GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) {
|
||||||
|
if (geometry_set.has(type)) {
|
||||||
|
GeometryComponent &component = geometry_set.get_component_for_write(type);
|
||||||
|
evalaute_attributes_on_result_component(component, attribute_outputs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate a node group to compute the output geometry.
|
* Evaluate a node group to compute the output geometry.
|
||||||
* Currently, this uses a fairly basic and inefficient algorithm that might compute things more
|
|
||||||
* often than necessary. It's going to be replaced soon.
|
|
||||||
*/
|
*/
|
||||||
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
||||||
Span<const NodeRef *> group_input_nodes,
|
Span<const NodeRef *> group_input_nodes,
|
||||||
const InputSocketRef &socket_to_compute,
|
const InputSocketRef &result_geometry_socket,
|
||||||
|
Span<const InputSocketRef *> attribute_output_sockets,
|
||||||
GeometrySet input_geometry_set,
|
GeometrySet input_geometry_set,
|
||||||
NodesModifierData *nmd,
|
NodesModifierData *nmd,
|
||||||
const ModifierEvalContext *ctx)
|
const ModifierEvalContext *ctx)
|
||||||
@@ -819,7 +890,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
for (const OutputSocketRef *socket : remaining_input_sockets) {
|
for (const OutputSocketRef *socket : remaining_input_sockets) {
|
||||||
const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type();
|
const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type();
|
||||||
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
|
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
|
||||||
initialize_group_input(*nmd, *socket->bsocket(), value_in);
|
initialize_group_input(*nmd, *socket, value_in);
|
||||||
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
|
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -828,7 +899,10 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
input_geometry_set.clear();
|
input_geometry_set.clear();
|
||||||
|
|
||||||
Vector<DInputSocket> group_outputs;
|
Vector<DInputSocket> group_outputs;
|
||||||
group_outputs.append({root_context, &socket_to_compute});
|
group_outputs.append({root_context, &result_geometry_socket});
|
||||||
|
for (const InputSocketRef *attribute_output : attribute_output_sockets) {
|
||||||
|
group_outputs.append({root_context, attribute_output});
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<geo_log::GeoLogger> geo_logger;
|
std::optional<geo_log::GeoLogger> geo_logger;
|
||||||
|
|
||||||
@@ -856,9 +930,13 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
|
nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_assert(eval_params.r_output_values.size() == 1);
|
BLI_assert(eval_params.r_output_values.size() >= 1);
|
||||||
GMutablePointer result = eval_params.r_output_values[0];
|
GeometrySet geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
|
||||||
return result.relocate_out<GeometrySet>();
|
|
||||||
|
evaluate_attributes_on_result_geometry(geometry_set,
|
||||||
|
eval_params.r_output_values.as_span().drop_front(1));
|
||||||
|
|
||||||
|
return geometry_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -939,13 +1017,27 @@ static void modifyGeometry(ModifierData *md,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputSocketRef *group_output = group_outputs[0];
|
const InputSocketRef &first_group_output = *group_outputs[0];
|
||||||
if (group_output->idname() != "NodeSocketGeometry") {
|
if (first_group_output.idname() != "NodeSocketGeometry") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry_set = compute_geometry(
|
/* TODO: Only add outputs that can be attributes and only outputs that have a corresponding name
|
||||||
tree, input_nodes, *group_outputs[0], std::move(geometry_set), nmd, ctx);
|
* to put the data in. */
|
||||||
|
Vector<const InputSocketRef *> attribute_output_sockets;
|
||||||
|
for (const InputSocketRef *group_output : group_outputs) {
|
||||||
|
if (socket_type_can_be_attribute(*group_output->bsocket())) {
|
||||||
|
attribute_output_sockets.append(group_output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry_set = compute_geometry(tree,
|
||||||
|
input_nodes,
|
||||||
|
first_group_output,
|
||||||
|
attribute_output_sockets,
|
||||||
|
std::move(geometry_set),
|
||||||
|
nmd,
|
||||||
|
ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
||||||
@@ -981,7 +1073,8 @@ static void draw_property_for_socket(uiLayout *layout,
|
|||||||
NodesModifierData *nmd,
|
NodesModifierData *nmd,
|
||||||
PointerRNA *bmain_ptr,
|
PointerRNA *bmain_ptr,
|
||||||
PointerRNA *md_ptr,
|
PointerRNA *md_ptr,
|
||||||
const bNodeSocket &socket)
|
const bNodeSocket &socket,
|
||||||
|
const int socket_index)
|
||||||
{
|
{
|
||||||
/* The property should be created in #MOD_nodes_update_interface with the correct type. */
|
/* The property should be created in #MOD_nodes_update_interface with the correct type. */
|
||||||
IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier);
|
IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier);
|
||||||
@@ -1026,7 +1119,7 @@ static void draw_property_for_socket(uiLayout *layout,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
if (socket_type_has_attribute_toggle(socket) &&
|
if (input_has_attribute_toggle(*nmd->node_group, socket_index) &&
|
||||||
USER_EXPERIMENTAL_TEST(&U, use_geometry_nodes_fields)) {
|
USER_EXPERIMENTAL_TEST(&U, use_geometry_nodes_fields)) {
|
||||||
const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
|
const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
|
||||||
use_attribute_suffix + "\"]";
|
use_attribute_suffix + "\"]";
|
||||||
@@ -1086,8 +1179,9 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||||||
PointerRNA bmain_ptr;
|
PointerRNA bmain_ptr;
|
||||||
RNA_main_pointer_create(bmain, &bmain_ptr);
|
RNA_main_pointer_create(bmain, &bmain_ptr);
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
|
int socket_index;
|
||||||
draw_property_for_socket(layout, nmd, &bmain_ptr, ptr, *socket);
|
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
|
||||||
|
draw_property_for_socket(layout, nmd, &bmain_ptr, ptr, *socket, socket_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1118,9 +1212,27 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||||||
modifier_panel_end(layout, ptr);
|
modifier_panel_end(layout, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void output_attributes_panel_draw(const bContext *C, Panel *panel)
|
||||||
|
{
|
||||||
|
uiLayout *layout = panel->layout;
|
||||||
|
Main *bmain = CTX_data_main(C);
|
||||||
|
|
||||||
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
|
||||||
|
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
|
||||||
|
|
||||||
|
uiLayoutSetPropSep(layout, true);
|
||||||
|
uiLayoutSetPropDecorate(layout, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void panelRegister(ARegionType *region_type)
|
static void panelRegister(ARegionType *region_type)
|
||||||
{
|
{
|
||||||
modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
|
PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
|
||||||
|
modifier_subpanel_register(region_type,
|
||||||
|
"output_attributes",
|
||||||
|
"Output Attributes",
|
||||||
|
nullptr,
|
||||||
|
output_attributes_panel_draw,
|
||||||
|
panel_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blendWrite(BlendWriter *writer, const ModifierData *md)
|
static void blendWrite(BlendWriter *writer, const ModifierData *md)
|
||||||
|
@@ -112,6 +112,24 @@ class OutputFieldDependency {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about how a node interacts with fields.
|
||||||
|
*/
|
||||||
|
struct FieldInferencingInterface {
|
||||||
|
Vector<InputSocketFieldType> inputs;
|
||||||
|
Vector<OutputFieldDependency> outputs;
|
||||||
|
|
||||||
|
friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
|
||||||
|
{
|
||||||
|
return a.inputs == b.inputs && a.outputs == b.outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes a single input or output socket. This is subclassed for different socket types.
|
* Describes a single input or output socket. This is subclassed for different socket types.
|
||||||
*/
|
*/
|
||||||
|
@@ -100,13 +100,12 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
|
|||||||
{
|
{
|
||||||
GeometryComponentFieldContext field_context{component, domain};
|
GeometryComponentFieldContext field_context{component, domain};
|
||||||
const int domain_size = component.attribute_domain_size(domain);
|
const int domain_size = component.attribute_domain_size(domain);
|
||||||
const IndexMask mask{IndexMask(domain_size)};
|
|
||||||
|
|
||||||
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
|
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
|
||||||
OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
|
OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
|
||||||
attribute_id, domain, data_type);
|
attribute_id, domain, data_type);
|
||||||
|
|
||||||
fn::FieldEvaluator evaluator{field_context, &mask};
|
fn::FieldEvaluator evaluator{field_context, domain_size};
|
||||||
evaluator.add_with_destination(field, output_attribute.varray());
|
evaluator.add_with_destination(field, output_attribute.varray());
|
||||||
evaluator.evaluate();
|
evaluator.evaluate();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user