Blender V4.3
node_parser.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#ifdef WITH_USD
6# include <pxr/base/tf/stringUtils.h>
7#endif
8
9#include "node_parser.h"
10
11#include "group_nodes.h"
12
13#include "BKE_node_runtime.hh"
14
16
17static const std::string TEXCOORD_NODE_NAME = "node_texcoord";
18
20
21NodeParser::NodeParser(MaterialX::GraphElement *graph,
22 const Depsgraph *depsgraph,
23 const Material *material,
24 const bNode *node,
25 const bNodeSocket *socket_out,
27 GroupNodeParser *group_parser,
28 const ExportParams &export_params)
29 : graph_(graph),
30 depsgraph_(depsgraph),
31 material_(material),
32 node_(node),
33 socket_out_(socket_out),
34 to_type_(to_type),
35 group_parser_(group_parser),
36 export_params_(export_params)
37{
39
41{
42 NodeItem res = empty();
43
44 /* Checking if node was already computed */
45 res.node = graph_->getNode(node_name());
46 if (!res.node) {
48 1,
49 "%s [%d] => %s",
50 node_->name,
51 node_->typeinfo->type,
52 NodeItem::type(to_type_).c_str());
53
54 res = compute();
55 if (res.node) {
56 res.node->setName(node_name());
57 }
58 }
59 if (NodeItem::is_arithmetic(to_type_)) {
60 res = res.convert(to_type_);
61 }
62 return res;
63}
64
65std::string NodeParser::node_name(bool with_out_socket) const
66{
67 auto valid_name = [](const std::string &name) {
68#ifdef WITH_USD
69 /* Node name should suite to MatX and USD valid names.
70 * It shouldn't start from '_', due to error occurred in Storm delegate. */
71 std::string res = MaterialX::createValidName(pxr::TfMakeValidIdentifier(name));
72#else
73 std::string res = MaterialX::createValidName(name);
74#endif
75 if (res[0] == '_') {
76 res = "node" + res;
77 }
78 return res;
79 };
80
81 std::string name = node_->name;
82 if (with_out_socket) {
83 if (node_->output_sockets().size() > 1) {
84 name += std::string("_") + socket_out_->name;
85 }
87 {
88 name += "_" + NodeItem::type(to_type_);
89 }
90 }
91#ifdef USE_MATERIALX_NODEGRAPH
92 return valid_name(name);
93#else
94
95 std::string prefix;
97 while (gr) {
98 const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gr->node_->id);
99 prefix = valid_name(ngroup->id.name) + "_" + prefix;
100 gr = gr->group_parser_;
101 }
102 return prefix + valid_name(name);
103#endif
104}
105
106NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type)
107{
108 return empty().create_node(category, type);
109}
110
111NodeItem NodeParser::create_node(const std::string &category,
112 NodeItem::Type type,
113 const NodeItem::Inputs &inputs)
114{
115 return empty().create_node(category, type, inputs);
116}
117
118NodeItem NodeParser::create_input(const std::string &name, const NodeItem &item)
119{
120 return empty().create_input(name, item);
121}
122
123NodeItem NodeParser::create_output(const std::string &name, const NodeItem &item)
124{
125 return empty().create_output(name, item);
126}
127
129{
130 return get_default(node_->input_by_identifier(name), to_type);
131}
132
134{
135 return get_default(node_->input_socket(index), to_type);
136}
137
139{
140 return get_input_link(node_->input_by_identifier(name), to_type, false);
141}
142
144{
145 return get_input_link(node_->input_socket(index), to_type, false);
146}
147
149{
150 return get_input_value(node_->input_by_identifier(name), to_type);
151}
152
154{
155 return get_input_value(node_->input_socket(index), to_type);
156}
157
159{
160 return get_default(node_->output_by_identifier(name), to_type);
161}
162
164{
165 return get_default(node_->output_socket(index), to_type);
166}
167
169{
170 return NodeItem(graph_);
171}
172
173NodeItem NodeParser::texcoord_node(NodeItem::Type type, const std::string &attribute_name)
174{
176 std::string name = TEXCOORD_NODE_NAME;
177 if (type == NodeItem::Type::Vector3) {
178 name += "_vector3";
179 }
180 NodeItem res = empty();
181 res.node = graph_->getNode(name);
182 if (!res.node) {
183 /* TODO: Use "Pref" generated texture coordinates for 3D, but needs
184 * work in USD and Hydra mesh export. */
185 const bool is_active_uvmap = attribute_name == "" ||
187 if (export_params_.new_active_uvmap_name == "st" && is_active_uvmap) {
188 res = create_node("texcoord", type);
189 }
190 else {
191 const std::string &geomprop = (is_active_uvmap) ? export_params_.new_active_uvmap_name :
192 attribute_name;
193 res = create_node("geompropvalue", type, {{"geomprop", val(geomprop)}});
194 }
195 res.node->setName(name);
196 }
197 return res;
198}
199
200NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_type)
201{
202 NodeItem res = empty();
203 if (!NodeItem::is_arithmetic(to_type) && to_type != NodeItem::Type::Any) {
204 return res;
205 }
206
207 switch (socket.type) {
208 case SOCK_CUSTOM:
209 /* Return empty */
210 break;
211 case SOCK_FLOAT: {
212 float v = socket.default_value_typed<bNodeSocketValueFloat>()->value;
213 res.value = MaterialX::Value::createValue<float>(v);
214 break;
215 }
216 case SOCK_VECTOR: {
217 const float *v = socket.default_value_typed<bNodeSocketValueVector>()->value;
218 res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
219 MaterialX::Vector3(v[0], v[1], v[2]));
220 break;
221 }
222 case SOCK_RGBA: {
223 const float *v = socket.default_value_typed<bNodeSocketValueRGBA>()->value;
224 res.value = MaterialX::Value::createValue<MaterialX::Color4>(
225 MaterialX::Color4(v[0], v[1], v[2], v[3]));
226 break;
227 }
228 default: {
229 CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type);
230 }
231 }
232 return res.convert(to_type);
233}
234
235NodeItem NodeParser::get_input_link(const bNodeSocket &socket,
237 bool use_group_default)
238{
239 const bNodeLink *link = socket.link;
240 if (!(link && link->is_used())) {
241 return empty();
242 }
243
244 const bNode *from_node = link->fromnode;
245
246 /* Passing NODE_REROUTE nodes */
247 while (from_node->is_reroute()) {
248 link = from_node->input_socket(0).link;
249 if (!(link && link->is_used())) {
250 return empty();
251 }
252 from_node = link->fromnode;
253 }
254
255 if (from_node->is_group()) {
256 return GroupNodeParser(graph_,
258 material_,
259 from_node,
260 link->fromsock,
261 to_type,
264 use_group_default)
265 .compute_full();
266 }
267 if (from_node->is_group_input()) {
268 return GroupInputNodeParser(graph_,
270 material_,
271 from_node,
272 link->fromsock,
273 to_type,
276 use_group_default)
277 .compute_full();
278 }
279
280 if (!from_node->typeinfo->materialx_fn) {
282 "Unsupported node: %s [%d]",
283 from_node->name,
284 from_node->typeinfo->type);
285 return empty();
286 }
287
288 NodeParserData data = {
290 from_node->typeinfo->materialx_fn(&data, const_cast<bNode *>(from_node), link->fromsock);
291 return data.result;
292}
293
295{
296 NodeItem res = get_input_link(socket, to_type, true);
297 if (!res) {
298 res = get_default(socket, to_type);
299 }
300 return res;
301}
302
303} // namespace blender::nodes::materialx
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLG_LOGREF_DECLARE_GLOBAL(var, id)
Definition CLG_log.h:145
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_CUSTOM
@ SOCK_RGBA
ATTR_WARN_UNUSED_RESULT const BMVert * v
NodeItem create_input(const std::string &name, const NodeItem &item) const
Definition node_item.cc:863
NodeItem convert(Type to_type) const
Definition node_item.cc:481
NodeItem create_output(const std::string &name, const NodeItem &item) const
Definition node_item.cc:880
std::vector< std::pair< std::string, NodeItem > > Inputs
Definition node_item.h:20
NodeItem create_node(const std::string &category, Type type) const
Definition node_item.cc:762
NodeItem get_input_value(const std::string &name, NodeItem::Type to_type)
MaterialX::GraphElement * graph_
Definition node_parser.h:28
NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, const bNode *node, const bNodeSocket *socket_out, NodeItem::Type to_type, GroupNodeParser *group_parser, const ExportParams &export_params)
NodeItem create_input(const std::string &name, const NodeItem &item)
NodeItem get_input_link(const std::string &name, NodeItem::Type to_type)
NodeItem texcoord_node(NodeItem::Type type=NodeItem::Type::Vector2, const std::string &attribute_name="")
NodeItem get_input_default(const std::string &name, NodeItem::Type to_type)
NodeItem get_output_default(const std::string &name, NodeItem::Type to_type)
NodeItem create_node(const std::string &category, NodeItem::Type type)
std::string node_name(bool with_out_socket=true) const
NodeItem create_output(const std::string &name, const NodeItem &item)
NodeItem val(const T &data) const
Definition node_parser.h:80
const Depsgraph * depsgraph
static Type to_type(const eGPUType type)
static const std::string TEXCOORD_NODE_NAME
struct CLG_LogRef * LOG_MATERIALX_SHADER
char name[66]
Definition DNA_ID.h:425
struct bNodeLink * link
bNodeTypeHandle * typeinfo
struct ID * id
char name[64]