forked from blender/blender
Support group nodes #22
@ -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()) {
|
||||||
|
@ -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
|
||||||
|
151
source/blender/nodes/shader/materialx/group_nodes.cc
Normal file
151
source/blender/nodes/shader/materialx/group_nodes.cc
Normal 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
|
41
source/blender/nodes/shader/materialx/group_nodes.h
Normal file
41
source/blender/nodes/shader/materialx/group_nodes.h
Normal 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
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user