Geometry Nodes: support outputting field without computing full node
Many nodes output anonymous attributes (e.g. the top selection in the Cylinder node). The actual data is only contained in the geometry output though. The field output just contains a reference to this data (essentially just the generated name of an attribute). This data can be output even without computing the geometry itself. As of right now, this only simplifies the code a bit, but does not have a bigger impact, because to use the anonymous attribute, you always need the geometry anyway. However, with the upcoming simulation nodes, it's possible to create the anonymous attribute in one frame and to access it in another frame. In the other frame we only need the anonymous attribute reference and don't have to create the actual geometry again. Skipping creating the actual attribute on the geometry can have a significant performance benefit.
This commit is contained in:
@@ -42,23 +42,6 @@ using fn::ValueOrField;
|
||||
using geo_eval_log::NamedAttributeUsage;
|
||||
using geo_eval_log::NodeWarningType;
|
||||
|
||||
/**
|
||||
* An anonymous attribute created by a node.
|
||||
*/
|
||||
class NodeAnonymousAttributeID : public AnonymousAttributeID {
|
||||
std::string long_name_;
|
||||
std::string socket_name_;
|
||||
|
||||
public:
|
||||
NodeAnonymousAttributeID(const Object &object,
|
||||
const ComputeContext &compute_context,
|
||||
const bNode &bnode,
|
||||
const StringRef identifier,
|
||||
const StringRef name);
|
||||
|
||||
std::string user_name() const override;
|
||||
};
|
||||
|
||||
class GeoNodeExecParams {
|
||||
private:
|
||||
const bNode &node_;
|
||||
@@ -66,18 +49,22 @@ class GeoNodeExecParams {
|
||||
const lf::Context &lf_context_;
|
||||
const Span<int> lf_input_for_output_bsocket_usage_;
|
||||
const Span<int> lf_input_for_attribute_propagation_to_output_;
|
||||
const FunctionRef<AnonymousAttributeIDPtr(int)> get_output_attribute_id_;
|
||||
|
||||
public:
|
||||
GeoNodeExecParams(const bNode &node,
|
||||
lf::Params ¶ms,
|
||||
const lf::Context &lf_context,
|
||||
const Span<int> lf_input_for_output_bsocket_usage,
|
||||
const Span<int> lf_input_for_attribute_propagation_to_output)
|
||||
const Span<int> lf_input_for_attribute_propagation_to_output,
|
||||
const FunctionRef<AnonymousAttributeIDPtr(int)> get_output_attribute_id)
|
||||
: node_(node),
|
||||
params_(params),
|
||||
lf_context_(lf_context),
|
||||
lf_input_for_output_bsocket_usage_(lf_input_for_output_bsocket_usage),
|
||||
lf_input_for_attribute_propagation_to_output_(lf_input_for_attribute_propagation_to_output)
|
||||
lf_input_for_attribute_propagation_to_output_(
|
||||
lf_input_for_attribute_propagation_to_output),
|
||||
get_output_attribute_id_(get_output_attribute_id)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -240,8 +227,6 @@ class GeoNodeExecParams {
|
||||
*/
|
||||
void error_message_add(const NodeWarningType type, StringRef message) const;
|
||||
|
||||
std::string attribute_producer_name() const;
|
||||
|
||||
void set_default_remaining_outputs();
|
||||
|
||||
void used_named_attribute(StringRef attribute_name, NamedAttributeUsage usage);
|
||||
@@ -268,14 +253,7 @@ class GeoNodeExecParams {
|
||||
return {};
|
||||
}
|
||||
const bNodeSocket &output_socket = node_.output_by_identifier(output_identifier);
|
||||
const GeoNodesLFUserData &user_data = *this->user_data();
|
||||
const ComputeContext &compute_context = *user_data.compute_context;
|
||||
return MEM_new<NodeAnonymousAttributeID>(__func__,
|
||||
*user_data.modifier_data->self_object,
|
||||
compute_context,
|
||||
node_,
|
||||
output_identifier,
|
||||
output_socket.name);
|
||||
return get_output_attribute_id_(output_socket.index());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -322,7 +322,9 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
|
||||
/**
|
||||
* For inputs this means that the input field is evaluated on all geometry inputs. For outputs
|
||||
* it means that this contains an anonymous attribute reference that is available on all geometry
|
||||
* outputs.
|
||||
* outputs. This sockets value does not have to be output manually in the node. It's done
|
||||
* automatically by #LazyFunctionForGeometryNode. This allows outputting this field even if the
|
||||
* geometry output does not have to be computed.
|
||||
*/
|
||||
Self &field_on_all()
|
||||
{
|
||||
|
||||
@@ -174,8 +174,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
break;
|
||||
}
|
||||
|
||||
const CPPType &type = field.cpp_type();
|
||||
|
||||
/* Run on the instances component separately to only affect the top level of instances. */
|
||||
if (domain == ATTR_DOMAIN_INSTANCE) {
|
||||
if (geometry_set.has_instances()) {
|
||||
@@ -198,34 +196,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
});
|
||||
}
|
||||
|
||||
GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>(
|
||||
std::move(attribute_id), type, params.attribute_producer_name())};
|
||||
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT: {
|
||||
params.set_output(output_identifier, Field<float>(output_field));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_FLOAT3: {
|
||||
params.set_output(output_identifier, Field<float3>(output_field));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_COLOR: {
|
||||
params.set_output(output_identifier, Field<ColorGeometry4f>(output_field));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_BOOL: {
|
||||
params.set_output(output_identifier, Field<bool>(output_field));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_INT32: {
|
||||
params.set_output(output_identifier, Field<int>(output_field));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
params.set_output("Geometry", geometry_set);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,11 +160,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
selection.span[i] = true;
|
||||
}
|
||||
selection.finish();
|
||||
|
||||
params.set_output(
|
||||
"Intersecting Edges",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name()));
|
||||
}
|
||||
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
|
||||
|
||||
@@ -81,9 +81,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (AnonymousAttributeIDPtr outer_points_id = params.get_output_anonymous_attribute_id_if_needed(
|
||||
"Outer Points")) {
|
||||
create_selection_output(output.get_component_for_write<CurveComponent>(), outer_points_id);
|
||||
params.set_output("Outer Points",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(outer_points_id), params.attribute_producer_name()));
|
||||
}
|
||||
params.set_output("Curve", std::move(output));
|
||||
}
|
||||
|
||||
@@ -200,21 +200,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
|
||||
params.set_output("Points", std::move(geometry_set));
|
||||
if (tangent_anonymous_id) {
|
||||
params.set_output("Tangent",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(tangent_anonymous_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (normal_anonymous_id) {
|
||||
params.set_output("Normal",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(normal_anonymous_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (rotation_anonymous_id) {
|
||||
params.set_output("Rotation",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(rotation_anonymous_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_curve_to_points_cc
|
||||
|
||||
@@ -590,19 +590,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
});
|
||||
|
||||
params.set_output("Points", std::move(geometry_set));
|
||||
|
||||
if (attribute_outputs.normal_id) {
|
||||
params.set_output(
|
||||
"Normal",
|
||||
AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.rotation_id) {
|
||||
params.set_output(
|
||||
"Rotation",
|
||||
AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc
|
||||
|
||||
@@ -1098,12 +1098,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
return;
|
||||
}
|
||||
|
||||
if (attribute_outputs.duplicate_index) {
|
||||
params.set_output(
|
||||
"Duplicate Index",
|
||||
AnonymousAttributeFieldInput::Create<int>(std::move(attribute_outputs.duplicate_index),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
}
|
||||
|
||||
|
||||
@@ -1376,16 +1376,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
});
|
||||
|
||||
params.set_output("Mesh", std::move(geometry_set));
|
||||
if (attribute_outputs.top_id) {
|
||||
params.set_output("Top",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.top_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
params.set_output("Side",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.side_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_extrude_mesh_cc
|
||||
|
||||
@@ -836,16 +836,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
|
||||
params.set_output("Curves", std::move(new_curves));
|
||||
if (index_attribute_id) {
|
||||
params.set_output("Closest Index",
|
||||
AnonymousAttributeFieldInput::Create<int>(std::move(index_attribute_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
if (weight_attribute_id) {
|
||||
params.set_output("Closest Weight",
|
||||
AnonymousAttributeFieldInput::Create<float>(
|
||||
std::move(weight_attribute_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_interpolate_curves_cc
|
||||
|
||||
@@ -851,29 +851,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
/* Transform the mesh so that the base of the cone is at the origin. */
|
||||
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
|
||||
|
||||
if (attribute_outputs.top_id) {
|
||||
params.set_output("Top",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.top_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.bottom_id) {
|
||||
params.set_output(
|
||||
"Bottom",
|
||||
AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
params.set_output("Side",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.side_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.uv_map_id) {
|
||||
params.set_output(
|
||||
"UV Map",
|
||||
AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.uv_map_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
|
||||
}
|
||||
|
||||
|
||||
@@ -112,12 +112,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
Mesh *mesh = create_cube_mesh(size, verts_x, verts_y, verts_z, uv_map_id.get());
|
||||
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
|
||||
|
||||
if (uv_map_id) {
|
||||
params.set_output("UV Map",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(uv_map_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc
|
||||
|
||||
@@ -122,29 +122,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
fill,
|
||||
attribute_outputs);
|
||||
|
||||
if (attribute_outputs.top_id) {
|
||||
params.set_output("Top",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.top_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.bottom_id) {
|
||||
params.set_output(
|
||||
"Bottom",
|
||||
AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.side_id) {
|
||||
params.set_output("Side",
|
||||
AnonymousAttributeFieldInput::Create<bool>(
|
||||
std::move(attribute_outputs.side_id), params.attribute_producer_name()));
|
||||
}
|
||||
if (attribute_outputs.uv_map_id) {
|
||||
params.set_output(
|
||||
"UV Map",
|
||||
AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.uv_map_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
|
||||
}
|
||||
|
||||
|
||||
@@ -205,12 +205,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
BKE_id_material_eval_ensure_default_slot(&mesh->id);
|
||||
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
|
||||
|
||||
if (uv_map_id) {
|
||||
params.set_output("UV Map",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(uv_map_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc
|
||||
|
||||
@@ -115,12 +115,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius, uv_map_id.get());
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
|
||||
|
||||
if (uv_map_id) {
|
||||
params.set_output("UV Map",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(uv_map_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
|
||||
|
||||
@@ -363,11 +363,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num, uv_map_id.get());
|
||||
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
|
||||
if (uv_map_id) {
|
||||
params.set_output("UV Map",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(uv_map_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc
|
||||
|
||||
@@ -348,9 +348,6 @@ static void create_attributes(GeoNodeExecParams ¶ms,
|
||||
*line_id, ATTR_DOMAIN_INSTANCE);
|
||||
line_attribute.span.copy_from(layout.line_numbers);
|
||||
line_attribute.finish();
|
||||
params.set_output("Line",
|
||||
AnonymousAttributeFieldInput::Create<int>(std::move(line_id),
|
||||
params.attribute_producer_name()));
|
||||
}
|
||||
|
||||
if (AnonymousAttributeIDPtr pivot_id = params.get_output_anonymous_attribute_id_if_needed(
|
||||
@@ -363,9 +360,6 @@ static void create_attributes(GeoNodeExecParams ¶ms,
|
||||
}
|
||||
|
||||
pivot_attribute.finish();
|
||||
params.set_output("Pivot Point",
|
||||
AnonymousAttributeFieldInput::Create<float3>(
|
||||
std::move(pivot_id), params.attribute_producer_name()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "BLI_cpp_types.hh"
|
||||
#include "BLI_dot_export.hh"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_hash_md5.h"
|
||||
#include "BLI_lazy_threading.hh"
|
||||
#include "BLI_map.hh"
|
||||
|
||||
@@ -102,6 +103,43 @@ static void lazy_function_interface_from_node(const bNode &node,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An anonymous attribute created by a node.
|
||||
*/
|
||||
class NodeAnonymousAttributeID : public AnonymousAttributeID {
|
||||
std::string long_name_;
|
||||
std::string socket_name_;
|
||||
|
||||
public:
|
||||
NodeAnonymousAttributeID(const Object &object,
|
||||
const ComputeContext &compute_context,
|
||||
const bNode &bnode,
|
||||
const StringRef identifier,
|
||||
const StringRef name)
|
||||
: socket_name_(name)
|
||||
{
|
||||
const ComputeContextHash &hash = compute_context.hash();
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << hash << "_" << object.id.name << "_" << bnode.identifier << "_" << identifier;
|
||||
long_name_ = ss.str();
|
||||
}
|
||||
{
|
||||
uint64_t hash_result[2];
|
||||
BLI_hash_md5_buffer(long_name_.data(), long_name_.size(), hash_result);
|
||||
std::stringstream ss;
|
||||
ss << ".a_" << std::hex << hash_result[0] << hash_result[1];
|
||||
name_ = ss.str();
|
||||
BLI_assert(name_.size() < MAX_CUSTOMDATA_LAYER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
std::string user_name() const override
|
||||
{
|
||||
return socket_name_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for most normal geometry nodes like Subdivision Surface and Set Position.
|
||||
*/
|
||||
@@ -117,6 +155,25 @@ class LazyFunctionForGeometryNode : public LazyFunction {
|
||||
* propagated to the output.
|
||||
*/
|
||||
const Span<int> lf_input_for_attribute_propagation_to_output_;
|
||||
/**
|
||||
* Maps #bNodeSocket::index_in_tree to input/output indices of the current lazy-function.
|
||||
*/
|
||||
const Span<int> lf_index_by_bsocket_;
|
||||
/**
|
||||
* A bool for every output bsocket. If true, the socket just outputs a field containing an
|
||||
* anonymous attribute id. If only such outputs are requested by other nodes, the node itself
|
||||
* does not have to execute.
|
||||
*/
|
||||
Vector<bool> is_attribute_output_bsocket_;
|
||||
|
||||
struct OutputAttributeID {
|
||||
int bsocket_index;
|
||||
AnonymousAttributeIDPtr attribute_id;
|
||||
};
|
||||
|
||||
struct Storage {
|
||||
Vector<OutputAttributeID, 1> attributes;
|
||||
};
|
||||
|
||||
public:
|
||||
LazyFunctionForGeometryNode(const bNode &node,
|
||||
@@ -126,7 +183,9 @@ class LazyFunctionForGeometryNode : public LazyFunction {
|
||||
: node_(node),
|
||||
lf_input_for_output_bsocket_usage_(r_lf_input_for_output_bsocket_usage),
|
||||
lf_input_for_attribute_propagation_to_output_(
|
||||
r_lf_input_for_attribute_propagation_to_output)
|
||||
r_lf_input_for_attribute_propagation_to_output),
|
||||
lf_index_by_bsocket_(r_lf_index_by_bsocket),
|
||||
is_attribute_output_bsocket_(node.output_sockets().size(), false)
|
||||
{
|
||||
BLI_assert(node.typeinfo->geometry_node_execute != nullptr);
|
||||
debug_name_ = node.name;
|
||||
@@ -137,6 +196,16 @@ class LazyFunctionForGeometryNode : public LazyFunction {
|
||||
if (relations == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!relations->available_relations.is_empty()) {
|
||||
/* Inputs are only used when an output is used that is not just outputting an anonymous
|
||||
* attribute field. */
|
||||
for (lf::Input &input : inputs_) {
|
||||
input.usage = lf::ValueUsage::Maybe;
|
||||
}
|
||||
for (const aal::AvailableRelation &relation : relations->available_relations) {
|
||||
is_attribute_output_bsocket_[relation.field_output] = true;
|
||||
}
|
||||
}
|
||||
Vector<const bNodeSocket *> handled_field_outputs;
|
||||
for (const aal::AvailableRelation &relation : relations->available_relations) {
|
||||
const bNodeSocket &output_bsocket = node.output_socket(relation.field_output);
|
||||
@@ -160,16 +229,90 @@ class LazyFunctionForGeometryNode : public LazyFunction {
|
||||
}
|
||||
}
|
||||
|
||||
void *init_storage(LinearAllocator<> &allocator) const override
|
||||
{
|
||||
return allocator.construct<Storage>().release();
|
||||
}
|
||||
|
||||
void destruct_storage(void *storage) const override
|
||||
{
|
||||
Storage *s = static_cast<Storage *>(storage);
|
||||
std::destroy_at(s);
|
||||
}
|
||||
|
||||
void execute_impl(lf::Params ¶ms, const lf::Context &context) const override
|
||||
{
|
||||
Storage *storage = static_cast<Storage *>(context.storage);
|
||||
GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
|
||||
BLI_assert(user_data != nullptr);
|
||||
|
||||
/* Lazily create the required anonymous attribute ids. */
|
||||
auto get_output_attribute_id = [&](const int output_bsocket_index) -> AnonymousAttributeIDPtr {
|
||||
for (const OutputAttributeID &node_output_attribute : storage->attributes) {
|
||||
if (node_output_attribute.bsocket_index == output_bsocket_index) {
|
||||
return node_output_attribute.attribute_id;
|
||||
}
|
||||
}
|
||||
const bNodeSocket &bsocket = node_.output_socket(output_bsocket_index);
|
||||
AnonymousAttributeIDPtr attribute_id = MEM_new<NodeAnonymousAttributeID>(
|
||||
__func__,
|
||||
*user_data->modifier_data->self_object,
|
||||
*user_data->compute_context,
|
||||
node_,
|
||||
bsocket.identifier,
|
||||
bsocket.name);
|
||||
storage->attributes.append({output_bsocket_index, attribute_id});
|
||||
return attribute_id;
|
||||
};
|
||||
|
||||
bool used_non_attribute_output_exists = false;
|
||||
for (const int output_bsocket_index : node_.output_sockets().index_range()) {
|
||||
const bNodeSocket &output_bsocket = node_.output_socket(output_bsocket_index);
|
||||
const int lf_index = lf_index_by_bsocket_[output_bsocket.index_in_tree()];
|
||||
if (lf_index == -1) {
|
||||
continue;
|
||||
}
|
||||
const lf::ValueUsage output_usage = params.get_output_usage(lf_index);
|
||||
if (output_usage == lf::ValueUsage::Unused) {
|
||||
continue;
|
||||
}
|
||||
if (is_attribute_output_bsocket_[output_bsocket_index]) {
|
||||
if (params.output_was_set(lf_index)) {
|
||||
continue;
|
||||
}
|
||||
this->output_anonymous_attribute_field(
|
||||
params, lf_index, get_output_attribute_id(output_bsocket_index));
|
||||
}
|
||||
else {
|
||||
if (output_usage == lf::ValueUsage::Used) {
|
||||
used_non_attribute_output_exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!used_non_attribute_output_exists) {
|
||||
/* Only attribute outputs are used currently, no need to evaluate the full node and its
|
||||
* inputs. */
|
||||
return;
|
||||
}
|
||||
|
||||
bool missing_input = false;
|
||||
for (const int lf_index : inputs_.index_range()) {
|
||||
if (params.try_get_input_data_ptr_or_request(lf_index) == nullptr) {
|
||||
missing_input = true;
|
||||
}
|
||||
}
|
||||
if (missing_input) {
|
||||
/* Wait until all inputs are available. */
|
||||
return;
|
||||
}
|
||||
|
||||
GeoNodeExecParams geo_params{node_,
|
||||
params,
|
||||
context,
|
||||
lf_input_for_output_bsocket_usage_,
|
||||
lf_input_for_attribute_propagation_to_output_};
|
||||
lf_input_for_attribute_propagation_to_output_,
|
||||
get_output_attribute_id};
|
||||
|
||||
geo_eval_log::TimePoint start_time = geo_eval_log::Clock::now();
|
||||
node_.typeinfo->geometry_node_execute(geo_params);
|
||||
@@ -182,6 +325,24 @@ class LazyFunctionForGeometryNode : public LazyFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the given anonymous attribute id as a field.
|
||||
*/
|
||||
void output_anonymous_attribute_field(lf::Params ¶ms,
|
||||
const int lf_index,
|
||||
AnonymousAttributeIDPtr attribute_id) const
|
||||
{
|
||||
const ValueOrFieldCPPType &value_or_field_cpp_type = *ValueOrFieldCPPType::get_from_self(
|
||||
*outputs_[lf_index].type);
|
||||
GField output_field{
|
||||
std::make_shared<AnonymousAttributeFieldInput>(std::move(attribute_id),
|
||||
value_or_field_cpp_type.value,
|
||||
node_.label_or_name() + TIP_(" node"))};
|
||||
void *r_value = params.get_output_data_ptr(lf_index);
|
||||
value_or_field_cpp_type.construct_from_field(r_value, std::move(output_field));
|
||||
params.output_set(lf_index);
|
||||
}
|
||||
|
||||
std::string input_name(const int index) const override
|
||||
{
|
||||
for (const bNodeSocket *bsocket : node_.output_sockets()) {
|
||||
|
||||
@@ -9,40 +9,10 @@
|
||||
|
||||
#include "NOD_geometry_exec.hh"
|
||||
|
||||
#include "BLI_hash_md5.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
NodeAnonymousAttributeID::NodeAnonymousAttributeID(const Object &object,
|
||||
const ComputeContext &compute_context,
|
||||
const bNode &bnode,
|
||||
const StringRef identifier,
|
||||
const StringRef name)
|
||||
: socket_name_(name)
|
||||
{
|
||||
const ComputeContextHash &hash = compute_context.hash();
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << hash << "_" << object.id.name << "_" << bnode.identifier << "_" << identifier;
|
||||
long_name_ = ss.str();
|
||||
}
|
||||
{
|
||||
uint64_t hash_result[2];
|
||||
BLI_hash_md5_buffer(long_name_.data(), long_name_.size(), hash_result);
|
||||
std::stringstream ss;
|
||||
ss << ".a_" << std::hex << hash_result[0] << hash_result[1];
|
||||
name_ = ss.str();
|
||||
BLI_assert(name_.size() < MAX_CUSTOMDATA_LAYER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
std::string NodeAnonymousAttributeID::user_name() const
|
||||
{
|
||||
return socket_name_;
|
||||
}
|
||||
|
||||
void GeoNodeExecParams::error_message_add(const NodeWarningType type,
|
||||
const StringRef message) const
|
||||
{
|
||||
@@ -153,11 +123,6 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string GeoNodeExecParams::attribute_producer_name() const
|
||||
{
|
||||
return node_.label_or_name() + TIP_(" node");
|
||||
}
|
||||
|
||||
void GeoNodeExecParams::set_default_remaining_outputs()
|
||||
{
|
||||
params_.set_default_remaining_outputs();
|
||||
|
||||
Reference in New Issue
Block a user