Geometry Nodes: Add Geometry Materials node

This adds a new `Geometry Materials` node that can get the list of materials from any geometry component that has them (i.e., Mesh, Point Cloud, Curve, Grease Pencil).

<img width="259" alt="image.png" src="attachments/f2742cdf-aef1-443c-a41e-0809c7430f0b">

This is a follow up to a PR that I closed about a half year ago (https://projects.blender.org/blender/blender/pulls/144628) now that lists are out of experimental!

Pull Request: https://projects.blender.org/blender/blender/pulls/161451

---------

Co-authored-by: Colin Basnett <5035660+cmbasnett@users.noreply.github.com>
This commit is contained in:
Colin Basnett 2026-07-30 17:05:25 +02:00
parent 1d51ce8478
commit b3d62684bc
4 changed files with 110 additions and 0 deletions

View file

@ -458,6 +458,8 @@ class NODE_MT_gn_material_base(node_add_menu.NodeMenu):
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "GeometryNodeGeometryMaterials")
layout.separator()
self.node_operator(layout, "GeometryNodeReplaceMaterial")
layout.separator()
self.node_operator(layout, "GeometryNodeInputMaterialIndex")

View file

@ -11003,6 +11003,7 @@ static void rna_def_nodes(BlenderRNA *brna)
define("GeometryNode", "GeometryNodeJoinGeometry");
define("GeometryNode", "GeometryNodeListGetItem");
define("GeometryNode", "GeometryNodeListLength");
define("GeometryNode", "GeometryNodeGeometryMaterials");
define("GeometryNode", "GeometryNodeMaterialSelection");
define("GeometryNode", "GeometryNodeMenuSwitch", def_geo_menu_switch);
define("GeometryNode", "GeometryNodeMergeByDistance");

View file

@ -98,6 +98,7 @@ set(SRC
nodes/node_geo_filter_list.cc
nodes/node_geo_flip_faces.cc
nodes/node_geo_foreach_geometry_element.cc
nodes/node_geo_geometry_materials.cc
nodes/node_geo_geometry_to_instance.cc
nodes/node_geo_get_attribute_names.cc
nodes/node_geo_get_bundle_item.cc

View file

@ -0,0 +1,106 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_material.hh"
#include "DNA_curves_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "NOD_geometry_nodes_list.hh"
#include "RNA_enum_types.hh"
#include "UI_interface_icons.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_geometry_materials {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry"_ustr);
b.add_input<decl::Menu>("Component Type"_ustr)
.static_items(rna_enum_geometry_component_type_items,
[](const EnumPropertyItem &item) {
return ELEM(GeometryComponent::Type(item.value),
GeometryComponent::Type::Mesh,
GeometryComponent::Type::PointCloud,
GeometryComponent::Type::Curve,
GeometryComponent::Type::GreasePencil);
})
.optional_label();
b.add_output<decl::Material>("Materials"_ustr).structure_type(StructureType::List);
}
static void node_geo_exec(GeoNodeExecParams params)
{
const GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"_ustr);
const GeometryComponent::Type component = params.extract_input<GeometryComponent::Type>(
"Component Type"_ustr);
Material **materials = nullptr;
int count = 0;
switch (component) {
case GeometryComponent::Type::Curve: {
if (const Curves *curves = geometry_set.get_curves()) {
materials = curves->mat;
count = curves->totcol;
}
break;
}
case GeometryComponent::Type::GreasePencil: {
if (const GreasePencil *grease_pencil = geometry_set.get_grease_pencil()) {
materials = grease_pencil->material_array;
count = grease_pencil->material_array_num;
}
break;
}
case GeometryComponent::Type::Mesh: {
if (const Mesh *mesh = geometry_set.get_mesh()) {
materials = mesh->mat;
count = mesh->totcol;
}
break;
}
case GeometryComponent::Type::PointCloud: {
if (const PointCloud *point_cloud = geometry_set.get_pointcloud()) {
materials = point_cloud->mat;
count = point_cloud->totcol;
}
break;
}
default:
break;
}
if (count == 0 || materials == nullptr) {
params.set_default_remaining_outputs();
return;
}
const CPPType &type = CPPType::get<Material *>();
GArray<> array(type, count, NoInitialization());
type.copy_construct_n(materials, array.data(), count);
params.set_output("Materials"_ustr, GList::from_garray(std::move(array)));
}
static void node_register()
{
static bke::bNodeType ntype;
geo_node_type_base(&ntype, "GeometryNodeGeometryMaterials"_ustr);
ntype.ui_name = "Geometry Materials";
ntype.ui_description = "Get a list of the materials used by a geometry component";
ntype.nclass = NODE_CLASS_GEOMETRY;
ntype.geometry_node_execute = node_geo_exec;
ntype.declare = node_declare;
bke::node_register_type(ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_geo_geometry_materials