This is part of D16858 but is also useful for other purposes. The changes to the node declaration in this commit allow us to figure out which fields might be evaluated on which geometries statically (without executing the node tree). This allows for deterministic anonymous attribute handling, which will be committed separately. Furthermore, this is necessary for usability features that help the user to avoid creating links that don't make sense (e.g. because a field can't be evaluated on a certain geometry). This also allows us to better separate fields which depend or don't depend on anonymous attributes. The main idea is that each node defines some relations between its sockets. There are four relations: * Propagate relation: Indicates that attributes on a geometry input can be propagated to a geometry output. * Reference relation: Indicates that an output field references an inputs field. So if the input field depends on an anonymous attribute, the output field does as well. * Eval relation: Indicates that an input field is evaluated on an input geometry. * Available relation: Indicates that an output field has anonymous attributes that are available on an output geometry. These relations can also be computed for node groups automatically, but that is not part of this commit.
56 lines
1.6 KiB
C++
56 lines
1.6 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "node_geometry_util.hh"
|
|
|
|
#include "UI_interface.h"
|
|
#include "UI_resources.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "BKE_material.h"
|
|
|
|
namespace blender::nodes::node_geo_material_replace_cc {
|
|
|
|
static void node_declare(NodeDeclarationBuilder &b)
|
|
{
|
|
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
|
|
b.add_input<decl::Material>(N_("Old"));
|
|
b.add_input<decl::Material>(N_("New"));
|
|
b.add_output<decl::Geometry>(N_("Geometry")).propagate_all();
|
|
}
|
|
|
|
static void node_geo_exec(GeoNodeExecParams params)
|
|
{
|
|
Material *old_material = params.extract_input<Material *>("Old");
|
|
Material *new_material = params.extract_input<Material *>("New");
|
|
|
|
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
|
|
|
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
|
for (const int i : IndexRange(mesh->totcol)) {
|
|
if (mesh->mat[i] == old_material) {
|
|
mesh->mat[i] = new_material;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
params.set_output("Geometry", std::move(geometry_set));
|
|
}
|
|
|
|
} // namespace blender::nodes::node_geo_material_replace_cc
|
|
|
|
void register_node_type_geo_material_replace()
|
|
{
|
|
namespace file_ns = blender::nodes::node_geo_material_replace_cc;
|
|
|
|
static bNodeType ntype;
|
|
|
|
geo_node_type_base(&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY);
|
|
ntype.declare = file_ns::node_declare;
|
|
ntype.geometry_node_execute = file_ns::node_geo_exec;
|
|
nodeRegisterType(&ntype);
|
|
}
|