Support group nodes #22

Merged
Bogdan Nagirniak merged 18 commits from BogdanNagirniak/blender:matx-group-nodes into matx-export-material 2023-09-18 12:49:19 +02:00
13 changed files with 345 additions and 50 deletions

View File

@ -81,6 +81,16 @@ void MaterialData::init()
MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx( MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx(
scene_delegate_->depsgraph, (Material *)id); scene_delegate_->depsgraph, (Material *)id);
pxr::UsdMtlxRead(doc, stage); pxr::UsdMtlxRead(doc, stage);
/* Logging stage: creating lambda stage_str() for not to call stage->ExportToString()
* if log won't be printed. */
auto stage_str = [&stage]() {
std::string str;
stage->ExportToString(&str);
return str;
};
ID_LOGN(2, "Stage:\n%s", stage_str().c_str());
if (pxr::UsdPrim materials = stage->GetPrimAtPath(pxr::SdfPath("/MaterialX/Materials"))) { if (pxr::UsdPrim materials = stage->GetPrimAtPath(pxr::SdfPath("/MaterialX/Materials"))) {
pxr::UsdPrimSiblingRange children = materials.GetChildren(); pxr::UsdPrimSiblingRange children = materials.GetChildren();
if (!children.empty()) { if (!children.empty()) {

View File

@ -150,10 +150,12 @@ if(WITH_MATERIALX)
materialx/material.cc materialx/material.cc
materialx/node_item.cc materialx/node_item.cc
materialx/node_parser.cc materialx/node_parser.cc
materialx/group_nodes.cc
materialx/material.h materialx/material.h
materialx/node_item.h materialx/node_item.h
materialx/node_parser.h materialx/node_parser.h
materialx/group_nodes.h
) )
list(APPEND LIB list(APPEND LIB
MaterialXCore MaterialXCore

View File

@ -0,0 +1,151 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "group_nodes.h"
#include "node_parser.h"
#include "BLI_vector.hh"
namespace blender::nodes::materialx {
NodeItem GroupNodeParser::compute()
{
NodeItem res = empty();
const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(node_->id);
ngroup->ensure_topology_cache();
const bNode *node_out = ngroup->group_output_node();
if (!node_out) {
return res;
}
MaterialX::GraphElement *graph = graph_;
#ifdef USE_MATERIALX_NODEGRAPH
std::string name = MaterialX::createValidName(ngroup->id.name);
MaterialX::NodeGraphPtr group_graph = graph_->getChildOfType<MaterialX::NodeGraph>(name);
if (!group_graph) {
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "<nodegraph name=%s>", name.c_str());
group_graph = graph_->addChild<MaterialX::NodeGraph>(name);
}
graph = group_graph.get();
#endif
NodeItem out =
GroupOutputNodeParser(
graph, depsgraph_, material_, node_out, socket_out_, NodeItem::Type::Any, this)
.compute_full();
#ifdef USE_MATERIALX_NODEGRAPH
/* We have to be in NodeParser's graph_, therefore copying output */
res.output = out.output;
#else
res = out;
#endif
return res;
}
NodeItem GroupNodeParser::compute_full()
{
NodeItem res = compute();
if (NodeItem::is_arithmetic(to_type_)) {
res = res.convert(to_type_);
}
return res;
}
NodeItem GroupOutputNodeParser::compute()
{
#ifdef USE_MATERIALX_NODEGRAPH
Vector<NodeItem> values;
for (auto socket_in : node_->input_sockets()) {
NodeItem value = get_input_value(socket_in->index(), NodeItem::Type::Any);
if (value.value) {
NodeItem constant = create_node("constant", value.type());
constant.set_input("value", value);
value = constant;
}
values.append(value);
}
Vector<NodeItem> outputs;
for (int i = 0; i < values.size(); ++i) {
if (values[i]) {
outputs.append(create_output("output" + std::to_string(i + 1), values[i]));
}
}
return outputs[socket_out_->index()];
#else
return get_input_value(socket_out_->index(), NodeItem::Type::Any);
#endif
}
NodeItem GroupOutputNodeParser::compute_full()
{
#ifdef USE_MATERIALX_NODEGRAPH
NodeItem res = empty();
/* Checking if output was already computed */
res.output = graph_->getOutput("output" + std::to_string(socket_out_->index() + 1));
if (res.output) {
return res;
}
CLOG_INFO(LOG_MATERIALX_SHADER,
1,
"%s [%d] => %s",
node_->name,
node_->typeinfo->type,
NodeItem::type(to_type_).c_str());
res = compute();
return res;
#else
return NodeParser::compute_full();
#endif
}
NodeItem GroupInputNodeParser::compute()
{
#ifdef USE_MATERIALX_NODEGRAPH
NodeItem value = group_parser_->get_input_link(socket_out_->index(), to_type_);
if (!value) {
return empty();
}
if (value.value) {
NodeItem constant = create_node("constant", value.type());
constant.set_input("value", value);
value = constant;
}
return create_input("input" + std::to_string(socket_out_->index() + 1), value);
#else
return group_parser_->get_input_link(socket_out_->index(), to_type_);
#endif
}
NodeItem GroupInputNodeParser::compute_full()
{
#ifdef USE_MATERIALX_NODEGRAPH
NodeItem res = empty();
/* Checking if output was already computed */
res.input = graph_->getInput("input" + std::to_string(socket_out_->index() + 1));
if (res.input) {
return res;
}
CLOG_INFO(LOG_MATERIALX_SHADER,
1,
"%s [%d] => %s",
node_->name,
node_->typeinfo->type,
NodeItem::type(to_type_).c_str());
res = compute();
return res;
#else
return NodeParser::compute_full();
#endif
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,41 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "node_parser.h"
/* TODO: pxr::UsdMtlxRead() doesn't perform nodegraphs.
* Uncomment USE_MATERIALX_NODEGRAPH after fixing it. */
//#define USE_MATERIALX_NODEGRAPH
namespace blender::nodes::materialx {
class GroupInputNodeParser;
class GroupNodeParser : public NodeParser {
friend NodeParser;
friend GroupInputNodeParser;
public:
using NodeParser::NodeParser;
NodeItem compute() override;
NodeItem compute_full() override;
};
class GroupOutputNodeParser : public NodeParser {
public:
using NodeParser::NodeParser;
NodeItem compute() override;
NodeItem compute_full() override;
};
class GroupInputNodeParser : public NodeParser {
public:
using NodeParser::NodeParser;
NodeItem compute() override;
NodeItem compute_full() override;
};
} // namespace blender::nodes::materialx

View File

@ -62,18 +62,18 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater
bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL);
if (output_node) { if (output_node) {
NodeParserData data = { NodeParserData data = {
doc.get(), depsgraph, material, NodeItem::Type::Material, NodeItem(doc.get())}; doc.get(), depsgraph, material, NodeItem::Type::Material, nullptr, NodeItem(doc.get())};
output_node->typeinfo->materialx_fn(&data, output_node, nullptr); output_node->typeinfo->materialx_fn(&data, output_node, nullptr);
} }
else { else {
DefaultMaterialNodeParser( DefaultMaterialNodeParser(
doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material) doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material, nullptr)
.compute_error(); .compute_error();
} }
} }
else { else {
DefaultMaterialNodeParser( DefaultMaterialNodeParser(
doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material) doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material, nullptr)
.compute(); .compute();
} }

View File

@ -66,7 +66,7 @@ std::string NodeItem::type(Type type)
{ {
switch (type) { switch (type) {
case Type::Any: case Type::Any:
return ""; return "any";
case Type::Multioutput: case Type::Multioutput:
return "multioutput"; return "multioutput";
case Type::String: case Type::String:
@ -103,9 +103,14 @@ std::string NodeItem::type(Type type)
return ""; return "";
} }
bool NodeItem::is_arithmetic(Type type)
{
return type >= Type::Float && type <= Type::Color4;
}
NodeItem::operator bool() const NodeItem::operator bool() const
{ {
return value || node; return value || node || input || output;
} }
NodeItem NodeItem::operator+(const NodeItem &other) const NodeItem NodeItem::operator+(const NodeItem &other) const
@ -604,8 +609,8 @@ NodeItem NodeItem::if_else(CompareOp op,
NodeItem NodeItem::extract(const int index) const NodeItem NodeItem::extract(const int index) const
{ {
NodeItem res = empty(); /* TODO: Add check if (value) { ... } */
res = create_node("extract", Type::Float); NodeItem res = create_node("extract", Type::Float);
res.set_input("in", *this); res.set_input("in", *this);
res.set_input("index", val(index)); res.set_input("index", val(index));
return res; return res;
@ -624,6 +629,9 @@ NodeItem::Type NodeItem::type() const
if (node) { if (node) {
return type(node->getType()); return type(node->getType());
} }
if (output) {
return type(output->getType());
}
return Type::Empty; return Type::Empty;
} }
@ -675,30 +683,59 @@ void NodeItem::set_input(const std::string &in_name, const NodeItem &item)
else if (item.node) { else if (item.node) {
node->setConnectedNode(in_name, item.node); node->setConnectedNode(in_name, item.node);
} }
else if (item.input) {
node->setAttribute("interfacename", item.input->getName());
}
else if (item.output) {
node->setConnectedOutput(in_name, item.output);
}
else { else {
CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", in_name.c_str()); CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", in_name.c_str());
} }
} }
void NodeItem::set_input_output(const std::string &in_name, NodeItem NodeItem::add_output(const std::string &out_name, Type out_type)
const NodeItem &item,
const std::string &out_name)
{ {
if (!item.node) { NodeItem res = empty();
res.output = node->addOutput(out_name, type(out_type));
return res;
}
NodeItem NodeItem::create_input(const std::string &name, const NodeItem &item) const
{
NodeItem res = empty();
res.input = graph_->addInput(name);
Type item_type = item.type();
if (item.node) {
res.input->setConnectedNode(item.node);
}
else {
BLI_assert_unreachable(); BLI_assert_unreachable();
} }
node->setConnectedNode(in_name, item.node); res.input->setType(type(item_type));
node->setConnectedOutput(in_name, item.node->getOutput(out_name));
return res;
} }
void NodeItem::add_output(const std::string &name, Type out_type) NodeItem NodeItem::create_output(const std::string &name, const NodeItem &item) const
{ {
node->addOutput(name, type(out_type)); NodeItem res = empty();
} res.output = graph_->addOutput(name);
bool NodeItem::is_arithmetic(Type type) Type item_type = item.type();
{ if (item.node) {
return type >= Type::Float && type <= Type::Color4; res.output->setConnectedNode(item.node);
}
else if (item.input) {
res.output->setInterfaceName(item.input->getName());
}
else {
BLI_assert_unreachable();
}
res.output->setType(type(item_type));
return res;
} }
NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2) NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2)
@ -776,10 +813,16 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(f
} }
} }
else { else {
/* TODO: Some of math functions (sin, cos, ...) doesn't work with Color types, NodeItem v = *this;
* we have to convert to Vector */ if (ELEM(type, Type::Color3, Type::Color4) &&
ELEM(category, "sin", "cos", "tan", "asin", "acos", "atan2", "sqrt", "ln", "exp"))
{
/* These functions haven't implementation in MaterialX, converting to Vector types */
BogdanNagirniak marked this conversation as resolved Outdated

typo fucntions and plural form

typo `fucntions` and plural form
type = type == Type::Color3 ? Type::Vector3 : Type::Vector4;
v = v.convert(type);
}
res = create_node(category, type); res = create_node(category, type);
res.set_input("in", *this); res.set_input("in", v);
} }
return res; return res;
} }

View File

@ -43,6 +43,8 @@ class NodeItem {
public: public:
MaterialX::ValuePtr value; MaterialX::ValuePtr value;
MaterialX::NodePtr node; MaterialX::NodePtr node;
MaterialX::InputPtr input;
MaterialX::OutputPtr output;
private: private:
MaterialX::GraphElement *graph_; MaterialX::GraphElement *graph_;
@ -102,15 +104,16 @@ class NodeItem {
NodeItem empty() const; NodeItem empty() const;
template<class T> NodeItem val(const T &data) const; template<class T> NodeItem val(const T &data) const;
Type type() const; Type type() const;
NodeItem create_node(const std::string &category, NodeItem::Type type) const;
/* Functions to set input and output */ /* Node functions */
NodeItem create_node(const std::string &category, NodeItem::Type type) const;
template<class T> void set_input(const std::string &in_name, const T &value, Type in_type); template<class T> void set_input(const std::string &in_name, const T &value, Type in_type);
void set_input(const std::string &in_name, const NodeItem &item); void set_input(const std::string &in_name, const NodeItem &item);
void set_input_output(const std::string &in_name, NodeItem add_output(const std::string &out_name, Type out_type);
const NodeItem &item,
const std::string &out_name); /* Output functions */
void add_output(const std::string &in_name, Type out_type); NodeItem create_input(const std::string &name, const NodeItem &item) const;
NodeItem create_output(const std::string &name, const NodeItem &item) const;
private: private:
static Type cast_types(NodeItem &item1, NodeItem &item2); static Type cast_types(NodeItem &item1, NodeItem &item2);

View File

@ -4,6 +4,8 @@
#include "node_parser.h" #include "node_parser.h"
#include "group_nodes.h"
#include "BKE_node_runtime.hh" #include "BKE_node_runtime.hh"
namespace blender::nodes::materialx { namespace blender::nodes::materialx {
@ -17,13 +19,15 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph,
const Material *material, const Material *material,
const bNode *node, const bNode *node,
const bNodeSocket *socket_out, const bNodeSocket *socket_out,
NodeItem::Type to_type) NodeItem::Type to_type,
GroupNodeParser *group_parser)
: graph_(graph), : graph_(graph),
depsgraph_(depsgraph), depsgraph_(depsgraph),
material_(material), material_(material),
node_(node), node_(node),
socket_out_(socket_out), socket_out_(socket_out),
to_type_(to_type) to_type_(to_type),
group_parser_(group_parser)
{ {
} }
@ -52,7 +56,7 @@ NodeItem NodeParser::compute_full()
return res; return res;
} }
std::string NodeParser::node_name() std::string NodeParser::node_name() const
{ {
std::string name = node_->name; std::string name = node_->name;
if (node_->output_sockets().size() > 1) { if (node_->output_sockets().size() > 1) {
@ -61,7 +65,18 @@ std::string NodeParser::node_name()
if (ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { if (ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) {
name += "_" + NodeItem::type(to_type_); name += "_" + NodeItem::type(to_type_);
} }
#ifdef USE_MATERIALX_NODEGRAPH
return MaterialX::createValidName(name); return MaterialX::createValidName(name);
#else
std::string prefix;
GroupNodeParser *gr = group_parser_;
while (gr) {
const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gr->node_->id);
prefix = MaterialX::createValidName(ngroup->id.name) + "_" + prefix;
gr = gr->group_parser_;
}
return prefix + MaterialX::createValidName(name);
#endif
} }
NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type) NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type)
@ -69,6 +84,16 @@ NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type typ
return empty().create_node(category, type); return empty().create_node(category, type);
} }
NodeItem NodeParser::create_input(const std::string &name, const NodeItem &item)
{
return empty().create_input(name, item);
}
NodeItem NodeParser::create_output(const std::string &name, const NodeItem &item)
{
return empty().create_output(name, item);
}
NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type)
{ {
return get_default(node_->input_by_identifier(name), to_type); return get_default(node_->input_by_identifier(name), to_type);
@ -129,6 +154,9 @@ NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_ty
{ {
NodeItem res = empty(); NodeItem res = empty();
switch (socket.type) { switch (socket.type) {
case SOCK_CUSTOM:
/* Return empty */
break;
case SOCK_FLOAT: { case SOCK_FLOAT: {
float v = socket.default_value_typed<bNodeSocketValueFloat>()->value; float v = socket.default_value_typed<bNodeSocketValueFloat>()->value;
res.value = MaterialX::Value::createValue<float>(v); res.value = MaterialX::Value::createValue<float>(v);
@ -163,7 +191,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to
const bNode *from_node = link->fromnode; const bNode *from_node = link->fromnode;
/* Passing NODE_REROUTE nodes */ /* Passing NODE_REROUTE nodes */
while (from_node->type == NODE_REROUTE) { while (from_node->is_reroute()) {
link = from_node->input_socket(0).link; link = from_node->input_socket(0).link;
if (!(link && link->is_used())) { if (!(link && link->is_used())) {
return empty(); return empty();
@ -171,6 +199,17 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to
from_node = link->fromnode; from_node = link->fromnode;
} }
if (from_node->is_group()) {
return GroupNodeParser(
graph_, depsgraph_, material_, from_node, link->fromsock, to_type, group_parser_)
.compute_full();
}
if (from_node->is_group_input()) {
return GroupInputNodeParser(
graph_, depsgraph_, material_, from_node, link->fromsock, to_type, group_parser_)
.compute_full();
}
if (!from_node->typeinfo->materialx_fn) { if (!from_node->typeinfo->materialx_fn) {
CLOG_WARN(LOG_MATERIALX_SHADER, CLOG_WARN(LOG_MATERIALX_SHADER,
"Unsupported node: %s [%d]", "Unsupported node: %s [%d]",
@ -179,7 +218,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to
return empty(); return empty();
} }
NodeParserData data = {graph_, depsgraph_, material_, to_type, empty()}; NodeParserData data = {graph_, depsgraph_, material_, to_type, group_parser_, empty()};
from_node->typeinfo->materialx_fn(&data, const_cast<bNode *>(from_node), link->fromsock); from_node->typeinfo->materialx_fn(&data, const_cast<bNode *>(from_node), link->fromsock);
return data.result; return data.result;
} }

View File

@ -16,6 +16,8 @@ namespace blender::nodes::materialx {
extern struct CLG_LogRef *LOG_MATERIALX_SHADER; extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
class GroupNodeParser;
class NodeParser { class NodeParser {
protected: protected:
MaterialX::GraphElement *graph_; MaterialX::GraphElement *graph_;
@ -24,6 +26,7 @@ class NodeParser {
const bNode *node_; const bNode *node_;
const bNodeSocket *socket_out_; const bNodeSocket *socket_out_;
NodeItem::Type to_type_; NodeItem::Type to_type_;
GroupNodeParser *group_parser_;
public: public:
NodeParser(MaterialX::GraphElement *graph, NodeParser(MaterialX::GraphElement *graph,
@ -31,15 +34,18 @@ class NodeParser {
const Material *material, const Material *material,
const bNode *node, const bNode *node,
const bNodeSocket *socket_out, const bNodeSocket *socket_out,
NodeItem::Type to_type); NodeItem::Type to_type,
GroupNodeParser *group_parser);
virtual ~NodeParser() = default; virtual ~NodeParser() = default;
virtual NodeItem compute() = 0; virtual NodeItem compute() = 0;
virtual NodeItem compute_full(); virtual NodeItem compute_full();
protected: protected:
std::string node_name(); std::string node_name() const;
NodeItem create_node(const std::string &category, NodeItem::Type type); NodeItem create_node(const std::string &category, NodeItem::Type type);
NodeItem create_input(const std::string &name, const NodeItem &item);
NodeItem create_output(const std::string &name, const NodeItem &item);
NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); NodeItem get_input_default(const std::string &name, NodeItem::Type to_type);
NodeItem get_input_default(int index, NodeItem::Type to_type); NodeItem get_input_default(int index, NodeItem::Type to_type);
NodeItem get_output_default(const std::string &name, NodeItem::Type to_type); NodeItem get_output_default(const std::string &name, NodeItem::Type to_type);
@ -71,6 +77,7 @@ struct NodeParserData {
const Depsgraph *depsgraph; const Depsgraph *depsgraph;
const Material *material; const Material *material;
NodeItem::Type to_type; NodeItem::Type to_type;
GroupNodeParser *group_parser;
NodeItem result; NodeItem result;
}; };
@ -91,7 +98,8 @@ struct NodeParserData {
void node_shader_materialx(void *data, struct bNode *node, struct bNodeSocket *out) \ void node_shader_materialx(void *data, struct bNode *node, struct bNodeSocket *out) \
{ \ { \
materialx::NodeParserData *d = reinterpret_cast<materialx::NodeParserData *>(data); \ materialx::NodeParserData *d = reinterpret_cast<materialx::NodeParserData *>(data); \
d->result = MaterialXNodeParser(d->graph, d->depsgraph, d->material, node, out, d->to_type) \ d->result = MaterialXNodeParser( \
d->graph, d->depsgraph, d->material, node, out, d->to_type, d->group_parser) \
.compute_full(); \ .compute_full(); \
} }

View File

@ -64,17 +64,17 @@ NODE_SHADER_MATERIALX_BEGIN
dielectric.set_input("scatter_mode", val(std::string("RT"))); dielectric.set_input("scatter_mode", val(std::string("RT")));
NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput);
artistic_ior.add_output("ior", NodeItem::Type::Color3);
artistic_ior.add_output("extinction", NodeItem::Type::Color3);
artistic_ior.set_input("reflectivity", color); artistic_ior.set_input("reflectivity", color);
artistic_ior.set_input("edge_color", color); artistic_ior.set_input("edge_color", color);
NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3);
NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3);
NodeItem conductor = create_node("conductor_bsdf", NodeItem::Type::BSDF); NodeItem conductor = create_node("conductor_bsdf", NodeItem::Type::BSDF);
if (normal) { if (normal) {
conductor.set_input("normal", normal); conductor.set_input("normal", normal);
} }
conductor.set_input_output("ior", artistic_ior, "ior"); conductor.set_input("ior", ior_out);
conductor.set_input_output("extinction", artistic_ior, "extinction"); conductor.set_input("extinction", extinction_out);
conductor.set_input("roughness", roughness); conductor.set_input("roughness", roughness);
NodeItem res = create_node("mix", NodeItem::Type::BSDF); NodeItem res = create_node("mix", NodeItem::Type::BSDF);
@ -82,7 +82,7 @@ NODE_SHADER_MATERIALX_BEGIN
res.set_input("bg", conductor); res.set_input("bg", conductor);
res.set_input("mix", val(0.5f)); res.set_input("mix", val(0.5f));
return res ; return res;
} }
#endif #endif
NODE_SHADER_MATERIALX_END NODE_SHADER_MATERIALX_END

View File

@ -70,10 +70,10 @@ NODE_SHADER_MATERIALX_BEGIN
NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3);
NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput);
artistic_ior.add_output("ior", NodeItem::Type::Color3);
artistic_ior.add_output("extinction", NodeItem::Type::Color3);
artistic_ior.set_input("reflectivity", color); artistic_ior.set_input("reflectivity", color);
artistic_ior.set_input("edge_color", color); artistic_ior.set_input("edge_color", color);
NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3);
NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3);
NodeItem res = create_node("conductor_bsdf", NodeItem::Type::BSDF); NodeItem res = create_node("conductor_bsdf", NodeItem::Type::BSDF);
if (normal) { if (normal) {
@ -82,8 +82,8 @@ NODE_SHADER_MATERIALX_BEGIN
if (tangent) { if (tangent) {
res.set_input("tangent", tangent); res.set_input("tangent", tangent);
} }
res.set_input_output("ior", artistic_ior, "ior"); res.set_input("ior", ior_out);
res.set_input_output("extinction", artistic_ior, "extinction"); res.set_input("extinction", extinction_out);
res.set_input("roughness", roughness); res.set_input("roughness", roughness);
return res; return res;

View File

@ -261,7 +261,7 @@ NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX #ifdef WITH_MATERIALX
{ {
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); NodeItem detail = get_input_default("Detail", NodeItem::Type::Float);
NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float);
NodeItem position = create_node("position", NodeItem::Type::Vector3); NodeItem position = create_node("position", NodeItem::Type::Vector3);
@ -269,9 +269,7 @@ NODE_SHADER_MATERIALX_BEGIN
NodeItem res = create_node("fractal3d", NodeItem::Type::Color3); NodeItem res = create_node("fractal3d", NodeItem::Type::Color3);
res.set_input("position", position); res.set_input("position", position);
if (detail.value) { res.set_input("octaves", val(int(detail.value->asA<float>())));
res.set_input("octaves", val(int(detail.value->asA<float>())));
}
res.set_input("lacunarity", lacunarity); res.set_input("lacunarity", lacunarity);
return res; return res;
} }