Geometry Nodes: geometry component type warning system

Previously, every node had to create warnings for unsupported input
geometry manually. Now this is automated. Nodes just have to specify
the geometry types they support in the node declaration.

Differential Revision: https://developer.blender.org/D12899
This commit is contained in:
Jacques Lucke 2021-10-26 20:00:03 +02:00
parent be3e09ecec
commit 0bfae1b120
Notes: blender-bot 2023-02-14 06:37:09 +01:00
Referenced by issue #92312, Warnings when unsupported geometry is passed into a node.
50 changed files with 269 additions and 120 deletions

View File

@ -318,6 +318,8 @@ struct GeometrySet {
bool include_instances,
blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const;
blender::Vector<GeometryComponentType> gather_component_types(bool include_instances, bool ignore_empty) const;
using ForeachSubGeometryCallback = blender::FunctionRef<void(GeometrySet &geometry_set)>;
void modify_geometry_sets(ForeachSubGeometryCallback callback);

View File

@ -527,6 +527,40 @@ void GeometrySet::gather_attributes_for_propagation(
delete dummy_component;
}
static void gather_component_types_recursive(const GeometrySet &geometry_set,
const bool include_instances,
const bool ignore_empty,
Vector<GeometryComponentType> &r_types)
{
for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
if (ignore_empty) {
if (component->is_empty()) {
continue;
}
}
r_types.append_non_duplicates(component->type());
}
if (!include_instances) {
return;
}
const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>();
if (instances == nullptr) {
return;
}
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_component_types_recursive(
instance_geometry_set, include_instances, ignore_empty, r_types);
});
}
blender::Vector<GeometryComponentType> GeometrySet::gather_component_types(
const bool include_instances, bool ignore_empty) const
{
Vector<GeometryComponentType> types;
gather_component_types_recursive(*this, include_instances, ignore_empty, types);
return types;
}
static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
Vector<GeometrySet *> &r_geometry_sets)
{

View File

@ -448,6 +448,7 @@ set(SRC
NOD_shader.h
NOD_socket.h
NOD_socket_declarations.hh
NOD_socket_declarations_geometry.hh
NOD_static_types.h
NOD_texture.h
NOD_type_conversions.hh

View File

@ -171,10 +171,16 @@ class GeoNodeExecParams {
this->check_input_access(identifier, &CPPType::get<T>());
#endif
GMutablePointer gvalue = this->extract_input(identifier);
return gvalue.relocate_out<T>();
T value = gvalue.relocate_out<T>();
if constexpr (std::is_same_v<T, GeometrySet>) {
this->check_input_geometry_set(identifier, value);
}
return value;
}
}
void check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const;
/**
* Get input as vector for multi input socket with the given identifier.
*
@ -211,7 +217,11 @@ class GeoNodeExecParams {
#endif
GPointer gvalue = provider_->get_input(identifier);
BLI_assert(gvalue.is_type<T>());
return *(const T *)gvalue.get();
const T &value = *(const T *)gvalue.get();
if constexpr (std::is_same_v<T, GeometrySet>) {
this->check_input_geometry_set(identifier, value);
}
return value;
}
}

View File

@ -212,14 +212,6 @@ class Image : public IDSocketDeclaration {
Image();
};
class Geometry : public SocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Geometry>;
bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
bool matches(const bNodeSocket &socket) const override;
};
/* -------------------------------------------------------------------- */
/** \name #FloatBuilder Inline Methods
* \{ */
@ -396,9 +388,7 @@ MAKE_EXTERN_SOCKET_DECLARATION(decl::Vector)
MAKE_EXTERN_SOCKET_DECLARATION(decl::Bool)
MAKE_EXTERN_SOCKET_DECLARATION(decl::Color)
MAKE_EXTERN_SOCKET_DECLARATION(decl::String)
MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry)
#undef MAKE_EXTERN_SOCKET_DECLARATION
} // namespace blender::nodes
/** \} */

View File

@ -0,0 +1,58 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "BKE_geometry_set.hh"
#include "NOD_socket_declarations.hh"
namespace blender::nodes::decl {
class GeometryBuilder;
class Geometry : public SocketDeclaration {
private:
blender::Vector<GeometryComponentType> supported_types_;
bool only_realized_data_ = false;
bool only_instances_ = false;
friend GeometryBuilder;
public:
using Builder = GeometryBuilder;
bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
bool matches(const bNodeSocket &socket) const override;
Span<GeometryComponentType> supported_types() const;
bool only_realized_data() const;
bool only_instances() const;
};
class GeometryBuilder : public SocketDeclarationBuilder<Geometry> {
public:
GeometryBuilder &supported_type(GeometryComponentType supported_type);
GeometryBuilder &supported_type(blender::Vector<GeometryComponentType> supported_types);
GeometryBuilder &only_realized_data(bool value = true);
GeometryBuilder &only_instances(bool value = true);
};
} // namespace blender::nodes::decl
namespace blender::nodes {
MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry)
}

View File

@ -32,6 +32,7 @@
#include "NOD_geometry.h"
#include "NOD_geometry_exec.hh"
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "node_util.h"

View File

@ -27,8 +27,10 @@ namespace blender::nodes {
static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry 1");
b.add_input<decl::Geometry>("Geometry 2").multi_input();
b.add_input<decl::Geometry>("Geometry 1")
.only_realized_data()
.supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Geometry>("Geometry 2").multi_input().supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Self Intersection");
b.add_input<decl::Bool>("Hole Tolerant");
b.add_output<decl::Geometry>("Geometry");
@ -83,11 +85,6 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
GeometrySet set_a;
if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
set_a = params.extract_input<GeometrySet>("Geometry 1");
if (set_a.has_instances()) {
params.error_message_add(
NodeWarningType::Info,
TIP_("Instances are not supported for the first geometry input, and will not be used"));
}
/* Note that it technically wouldn't be necessary to realize the instances for the first
* geometry input, but the boolean code expects the first shape for the difference operation
* to be a single mesh. */

View File

@ -35,7 +35,7 @@ namespace blender::nodes {
static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_output<decl::Geometry>("Mesh");
}

View File

@ -29,7 +29,7 @@ namespace blender::nodes {
static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Int>("Count").default_value(1).min(1).max(1000).supports_field();
b.add_input<decl::Float>("Radius")
.min(0.0f)

View File

@ -21,7 +21,7 @@ namespace blender::nodes {
static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_output<decl::Float>("Length");
}

View File

@ -34,7 +34,7 @@ namespace blender::nodes {
static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Int>("Count").default_value(10).min(1).max(100000).supports_field();
b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).supports_field().subtype(
PROP_DISTANCE);

View File

@ -24,7 +24,7 @@ namespace blender::nodes {
static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}

View File

@ -27,7 +27,8 @@ namespace blender::nodes {
static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").only_realized_data().supported_type(
GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
b.add_input<decl::Float>("Length").min(0.0f).subtype(PROP_DISTANCE).supports_field();
@ -237,12 +238,6 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params)
params.set_output("Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
};
if (geometry_set.has_instances()) {
params.error_message_add(
NodeWarningType::Info,
TIP_("The node only supports realized curve data, instances are ignored"));
}
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
if (component == nullptr) {
return return_default();

View File

@ -25,7 +25,7 @@ namespace blender::nodes {
static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}

View File

@ -27,7 +27,7 @@ namespace blender::nodes {
static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}

View File

@ -33,7 +33,7 @@ namespace blender::nodes {
static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Int>("Cuts").default_value(1).min(0).max(1000).supports_field();
b.add_output<decl::Geometry>("Geometry");
}

View File

@ -27,8 +27,10 @@ namespace blender::nodes {
static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Profile Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Geometry>("Profile Curve")
.only_realized_data()
.supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Fill Caps")
.description(
"If the profile spline is cyclic, fill the ends of the generated mesh with N-gons");
@ -58,18 +60,6 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
const bool fill_caps = params.extract_input<bool>("Fill Caps");
if (profile_set.has_instances()) {
params.error_message_add(NodeWarningType::Error,
TIP_("Instances are not supported in the profile input"));
params.set_output("Mesh", GeometrySet());
return;
}
if (!profile_set.has_curve() && !profile_set.is_empty()) {
params.error_message_add(NodeWarningType::Warning,
TIP_("No curve data available in the profile input"));
}
bool has_curve = false;
curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (geometry_set.has_curve()) {
@ -79,11 +69,6 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
});
if (!has_curve && !curve_set.is_empty()) {
params.error_message_add(NodeWarningType::Warning,
TIP_("No curve data available in curve input"));
}
params.set_output("Mesh", std::move(curve_set));
}

View File

@ -30,7 +30,7 @@ namespace blender::nodes {
static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Int>("Count").default_value(10).min(2).max(100000);
b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
b.add_output<decl::Geometry>("Points");

View File

@ -28,7 +28,7 @@ namespace blender::nodes {
static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
b.add_input<decl::Geometry>("Curve").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Float>("Start").min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
b.add_input<decl::Float>("End")
.min(0.0f)

View File

@ -42,7 +42,7 @@ namespace blender::nodes {
static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Float>("Distance Min").min(0.0f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>("Density Max").default_value(10.0f).min(0.0f);

View File

@ -26,7 +26,7 @@ namespace blender::nodes {
static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Mesh");
b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Mesh");
}

View File

@ -23,7 +23,7 @@ namespace blender::nodes {
static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Instances");
b.add_input<decl::Geometry>("Instances").supported_type(GEO_COMPONENT_TYPE_INSTANCES);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Vector>("Position").implicit_field();
b.add_input<decl::Float>("Radius")

View File

@ -28,7 +28,7 @@ namespace blender::nodes {
static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Material>("Old");
b.add_input<decl::Material>("New");
b.add_output<decl::Geometry>("Geometry");

View File

@ -27,7 +27,7 @@ namespace blender::nodes {
static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
b.add_output<decl::Geometry>("Geometry");
}

View File

@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Mesh");
b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}

View File

@ -30,7 +30,7 @@ namespace blender::nodes {
static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Mesh");
b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
b.add_input<decl::Vector>("Position").implicit_field();
b.add_input<decl::Float>("Radius")

View File

@ -27,7 +27,7 @@ namespace blender::nodes {
static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Points");
b.add_input<decl::Geometry>("Points").supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
b.add_output<decl::Geometry>("Mesh");
}

View File

@ -32,7 +32,7 @@ namespace blender::nodes {
static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f);
b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);

View File

@ -31,7 +31,8 @@ namespace blender::nodes {
static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Target");
b.add_input<decl::Geometry>("Target").only_realized_data().supported_type(
{GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
b.add_input<decl::Vector>("Source Position").implicit_field();
b.add_output<decl::Vector>("Position").dependent_field();
b.add_output<decl::Float>("Distance").dependent_field();
@ -214,12 +215,6 @@ static void geo_node_proximity_exec(GeoNodeExecParams params)
params.set_output("Distance", fn::make_constant_field<float>(0.0f));
};
if (geometry_set_target.has_instances()) {
params.error_message_add(
NodeWarningType::Info,
TIP_("The node only supports realized mesh or point cloud data, instances are ignored"));
}
if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
return return_default();
}

View File

@ -31,7 +31,9 @@ namespace blender::nodes {
static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Target Geometry");
b.add_input<decl::Geometry>("Target Geometry")
.only_realized_data()
.supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Vector>("Attribute").hide_value().supports_field();
b.add_input<decl::Float>("Attribute", "Attribute_001").hide_value().supports_field();
@ -389,26 +391,11 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
});
};
if (target.has_instances()) {
if (target.has_realized_data()) {
params.error_message_add(
NodeWarningType::Info,
TIP_("The node only supports realized mesh data, instances are ignored"));
}
else {
params.error_message_add(NodeWarningType::Error,
TIP_("The target geometry must contain realized data"));
return return_default();
}
}
if (target.is_empty()) {
return return_default();
}
if (!target.has_mesh()) {
params.error_message_add(NodeWarningType::Error,
TIP_("The target geometry must contain a mesh"));
return return_default();
}

View File

@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").only_instances();
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).supports_field();
b.add_input<decl::Vector>("Pivot Point").subtype(PROP_TRANSLATION).supports_field();

View File

@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").only_instances();
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Vector>("Scale").subtype(PROP_XYZ).default_value({1, 1, 1}).supports_field();
b.add_input<decl::Vector>("Center").subtype(PROP_TRANSLATION).supports_field();

View File

@ -25,7 +25,7 @@ namespace blender::nodes {
static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Vector>("Position").implicit_field();
b.add_output<decl::Geometry>("Geometry");

View File

@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Float>("Radius").min(0.0f).default_value(1.0f).supports_field().subtype(
PROP_DISTANCE);

View File

@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Float>("Tilt").subtype(PROP_ANGLE).supports_field();
b.add_output<decl::Geometry>("Geometry");

View File

@ -28,7 +28,7 @@ namespace blender::nodes {
static void geo_node_set_material_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Material>("Material").hide_label();
b.add_output<decl::Geometry>("Geometry");

View File

@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Int>("Material Index").supports_field().min(0);
b.add_output<decl::Geometry>("Geometry");

View File

@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Float>("Radius").default_value(0.05f).min(0.0f).supports_field().subtype(
PROP_DISTANCE);

View File

@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Bool>("Shade Smooth").supports_field();
b.add_output<decl::Geometry>("Geometry");

View File

@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Bool>("Cyclic").supports_field();
b.add_output<decl::Geometry>("Geometry");

View File

@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Int>("Resolution").default_value(12).supports_field();
b.add_output<decl::Geometry>("Geometry");

View File

@ -31,7 +31,7 @@ namespace blender::nodes {
static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
b.add_input<decl::Float>("Crease")
.default_value(0.0f)

View File

@ -40,7 +40,8 @@ namespace blender::nodes {
static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Target");
b.add_input<decl::Geometry>("Target").only_realized_data().supported_type(
{GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
b.add_input<decl::Vector>("Attribute").hide_value().supports_field();
b.add_input<decl::Float>("Attribute", "Attribute_001").hide_value().supports_field();
@ -747,21 +748,9 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
});
};
if (geometry.has_instances()) {
if (geometry.has_realized_data()) {
params.error_message_add(
NodeWarningType::Info,
TIP_("Only realized geometry is supported, instances will not be used"));
}
else {
params.error_message_add(NodeWarningType::Error,
TIP_("Target geometry must contain realized data"));
return return_default();
}
/* Since the instances are not used, there is no point in keeping
* a reference to them while the field is passed around. */
geometry.remove(GEO_COMPONENT_TYPE_INSTANCES);
}
/* Since the instances are not used, there is no point in keeping
* a reference to them while the field is passed around. */
geometry.remove(GEO_COMPONENT_TYPE_INSTANCES);
GField output_field;
switch (mapping) {
@ -791,8 +780,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
}
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
if (geometry.has_curve() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
params.error_message_add(NodeWarningType::Warning,
TIP_("Curve targets are not currently supported"));
return return_default();
}
auto fn = std::make_unique<NearestTransferFunction>(

View File

@ -22,7 +22,7 @@ namespace blender::nodes {
static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").only_instances();
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION).supports_field();
b.add_input<decl::Bool>("Local Space").default_value(true).supports_field();

View File

@ -31,7 +31,7 @@ namespace blender::nodes {
static void geo_node_triangulate_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Geometry>("Geometry").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>("Minimum Vertices").default_value(4).min(4).max(10000);
b.add_output<decl::Geometry>("Geometry");
}

View File

@ -39,7 +39,7 @@ namespace blender::nodes {
static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Volume");
b.add_input<decl::Geometry>("Volume").supported_type(GEO_COMPONENT_TYPE_VOLUME);
b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
b.add_input<decl::Float>("Threshold").default_value(0.1f).min(0.0f);

View File

@ -15,6 +15,7 @@
*/
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
namespace blender::nodes {
#define MAKE_EXTERN_SOCKET_IMPLEMENTATION(TYPE) \

View File

@ -36,6 +36,71 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
const GeometrySet &geometry_set) const
{
const int input_index = provider_->dnode->input_by_identifier(identifier).index();
const SocketDeclaration &decl = *provider_->dnode->declaration()->inputs()[input_index];
const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
if (geo_decl == nullptr) {
return;
}
const bool only_realized_data = geo_decl->only_realized_data();
const bool only_instances = geo_decl->only_instances();
const Span<GeometryComponentType> supported_types = geo_decl->supported_types();
if (only_realized_data) {
if (geometry_set.has_instances()) {
this->error_message_add(NodeWarningType::Info, "Instances in input geometry are ignored");
}
}
if (only_instances) {
if (geometry_set.has_realized_data()) {
this->error_message_add(NodeWarningType::Info,
"Realized data in input geometry are ignored");
}
}
if (supported_types.is_empty()) {
/* Assume all types are supported. */
return;
}
const Vector<GeometryComponentType> types_in_geometry = geometry_set.gather_component_types(
true, true);
for (const GeometryComponentType type : types_in_geometry) {
if (type == GEO_COMPONENT_TYPE_INSTANCES) {
continue;
}
if (supported_types.contains(type)) {
continue;
}
std::string message = TIP_("Input geometry has unsupported type: ");
switch (type) {
case GEO_COMPONENT_TYPE_MESH: {
message += TIP_("Mesh");
break;
}
case GEO_COMPONENT_TYPE_POINT_CLOUD: {
message += TIP_("Point Cloud");
break;
}
case GEO_COMPONENT_TYPE_INSTANCES: {
BLI_assert_unreachable();
break;
}
case GEO_COMPONENT_TYPE_VOLUME: {
message += TIP_("Volume");
break;
}
case GEO_COMPONENT_TYPE_CURVE: {
message += TIP_("Curve");
break;
}
}
this->error_message_add(NodeWarningType::Info, std::move(message));
}
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
{
for (const InputSocketRef *socket : provider_->dnode->inputs()) {

View File

@ -15,6 +15,7 @@
*/
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "BKE_node.h"
@ -333,6 +334,46 @@ bool Geometry::matches(const bNodeSocket &socket) const
return true;
}
Span<GeometryComponentType> Geometry::supported_types() const
{
return supported_types_;
}
bool Geometry::only_realized_data() const
{
return only_realized_data_;
}
bool Geometry::only_instances() const
{
return only_instances_;
}
GeometryBuilder &GeometryBuilder::supported_type(GeometryComponentType supported_type)
{
decl_->supported_types_ = {supported_type};
return *this;
}
GeometryBuilder &GeometryBuilder::supported_type(
blender::Vector<GeometryComponentType> supported_types)
{
decl_->supported_types_ = std::move(supported_types);
return *this;
}
GeometryBuilder &GeometryBuilder::only_realized_data(bool value)
{
decl_->only_realized_data_ = value;
return *this;
}
GeometryBuilder &GeometryBuilder::only_instances(bool value)
{
decl_->only_instances_ = value;
return *this;
}
/** \} */
} // namespace blender::nodes::decl