MaterialX: add convert nodes #15

Merged
Bogdan Nagirniak merged 8 commits from matx-add-convert-nodes into matx-export-material 2023-09-08 16:55:00 +02:00
34 changed files with 808 additions and 294 deletions
Showing only changes of commit e51f34488b - Show all commits

View File

@ -147,27 +147,39 @@ set(LIB
if(WITH_MATERIALX)
list(APPEND SRC
materialx/material.cc
materialx/nodes/add_shader.cc
materialx/nodes/blackbody.cc
materialx/nodes/brightness.cc
materialx/nodes/bsdf_diffuse.cc
materialx/nodes/bsdf_glass.cc
materialx/nodes/bsdf_glossy.cc
materialx/nodes/bsdf_principled.cc
materialx/nodes/bsdf_refraction.cc
materialx/nodes/bsdf_sheen.cc
materialx/nodes/bsdf_toon.cc
materialx/nodes/bsdf_translucent.cc
materialx/nodes/bsdf_transparent.cc
materialx/nodes/clamp.cc
materialx/nodes/emission.cc
materialx/nodes/huesatval.cc
materialx/nodes/invert.cc
materialx/nodes/map_range.cc
materialx/nodes/math.cc
materialx/nodes/mix_rgb.cc
materialx/nodes/mix_shader.cc
materialx/nodes/node_item.cc
materialx/nodes/node_parser.cc
materialx/nodes/normal_map.cc
materialx/nodes/output_material.cc
materialx/nodes/sepcomb_color.cc
materialx/nodes/sepcomb_xyz.cc
materialx/nodes/subsurface_scattering.cc
materialx/nodes/tex_checker.cc
materialx/nodes/tex_environment.cc
materialx/nodes/tex_image.cc
materialx/nodes/tex_noise.cc
materialx/nodes/tex_noise.cc
materialx/nodes/vector_math.cc
materialx/material.h
materialx/nodes/node_item.h
materialx/nodes/node_parser.h

View File

@ -17,9 +17,7 @@ namespace blender::nodes::materialx {
CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader");
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
Material *material,
const std::string &socket_name)
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material)
{
CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name);
@ -27,14 +25,14 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
if (material->use_nodes) {
material->nodetree->ensure_topology_cache();
bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL);
OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute(socket_name);
OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute_full();
}
else {
OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default();
}
CLOG_INFO(LOG_MATERIALX_SHADER,
2,
1,
"Material: %s\n%s",
material->id.name,
MaterialX::writeToXmlString(doc).c_str());

View File

@ -15,8 +15,6 @@ namespace blender::nodes::materialx {
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
Material *material,
const std::string &socket_name = "Surface");
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material);
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,42 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem AddShaderNodeParser::compute()
{
NodeItem res = empty();
switch (shader_type_) {
case NodeItem::Type::BSDF:
case NodeItem::Type::EDF: {
NodeItem shader1 = get_input_shader(0, shader_type_);
NodeItem shader2 = get_input_shader(1, shader_type_);
if (shader1 && !shader2) {
res = shader1;
}
else if (!shader1 && shader2) {
res = shader2;
}
else if (shader1 && shader2) {
res = shader1 + shader2;
}
break;
}
case NodeItem::Type::SurfaceShader: {
res = get_input_shader(0, shader_type_);
if (!res) {
res = get_input_shader(1, shader_type_);
}
break;
}
default:
BLI_assert_unreachable();
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -13,7 +13,7 @@ NodeItem BrightContrastNodeParser::compute()
NodeItem contrast = get_input_value("Contrast", NodeItem::Type::Float);
/* This formula was given from OSL shader code in Cycles. */
return (bright + color * (contrast + value(1.0f)) - contrast * value(0.5f)).max(value(0.0f));
return (bright + color * (contrast + val(1.0f)) - contrast * val(0.5f)).max(val(0.0f));
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,28 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFDiffuseNodeParser::compute()
{
if (shader_type_ != NodeItem::Type::BSDF) {
return empty();
}
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float);
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF);
res.set_input("color", color);
res.set_input("roughness", roughness);
if (normal) {
res.set_input("normal", normal);
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFGlassNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFGlossyNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -8,6 +8,11 @@ namespace blender::nodes::materialx {
NodeItem BSDFPrincipledNodeParser::compute()
{
if (shader_type_ != NodeItem::Type::SurfaceShader) {
/* TODO: implement for BSDF and EDF */
return empty();
}
NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3);
NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float);
@ -40,13 +45,13 @@ NodeItem BSDFPrincipledNodeParser::compute()
NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float);
// transparency = 1.0 - alpha
NodeItem normal = get_input_link("Normal");
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal");
NodeItem tangent = get_input_link("Tangent");
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3);
NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3);
/* Creating standard_surface */
NodeItem res = create_node("standard_surface", "surfaceshader");
res.set_input("base", 1.0, "float");
NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader);
res.set_input("base", val(1.0f));
res.set_input("base_color", base_color);
res.set_input("diffuse_roughness", roughness);
if (normal) {

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFRefractionNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFSheenNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFToonNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFTranslucentNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFTransparentNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,23 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem EmissionNodeParser::compute()
{
if (shader_type_ != NodeItem::Type::EDF) {
return empty();
}
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
NodeItem strength = get_input_value("Strength", NodeItem::Type::Float);
NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF);
res.set_input("color", color * strength);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -12,19 +12,19 @@ NodeItem HueSatValNodeParser::compute()
* source\blender\nodes\texture\nodes\node_texture_hueSatVal.cc */
NodeItem hue = get_input_value("Hue", NodeItem::Type::Float);
NodeItem saturation = get_input_value("Saturation", NodeItem::Type::Float);
NodeItem val = get_input_value("Value", NodeItem::Type::Float);
NodeItem value = get_input_value("Value", NodeItem::Type::Float);
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
/* Modifier to follow Cycles result */
hue = hue - value(0.5f);
hue = hue - val(0.5f);
NodeItem combine = create_node("combine3", "vector3");
NodeItem combine = create_node("combine3", NodeItem::Type::Vector3);
combine.set_input("in1", hue);
combine.set_input("in2", saturation);
combine.set_input("in3", val);
combine.set_input("in3", value);
NodeItem res = create_node("hsvadjust", "color3");
NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3);
res.set_input("in", color);
res.set_input("amount", combine);
return res;

View File

@ -12,7 +12,7 @@ NodeItem MapRangeNodeParser::compute()
const NodeMapRange *map_range = static_cast<NodeMapRange *>(node_->storage);
NodeItem::Type type;
NodeItem val = empty();
NodeItem value = empty();
NodeItem from_min = empty();
NodeItem from_max = empty();
NodeItem to_min = empty();
@ -20,7 +20,7 @@ NodeItem MapRangeNodeParser::compute()
switch (map_range->data_type) {
case CD_PROP_FLOAT:
type = NodeItem::Type::Float;
val = get_input_value("Value", type);
value = get_input_value("Value", type);
from_min = get_input_value(1, type);
from_max = get_input_value(2, type);
to_min = get_input_value(3, type);
@ -28,7 +28,7 @@ NodeItem MapRangeNodeParser::compute()
break;
case CD_PROP_FLOAT3:
type = NodeItem::Type::Vector3;
val = get_input_value("Vector", type);
value = get_input_value("Vector", type);
from_min = get_input_value(7, type);
from_max = get_input_value(8, type);
to_min = get_input_value(9, type);
@ -38,13 +38,13 @@ NodeItem MapRangeNodeParser::compute()
BLI_assert_unreachable();
}
NodeItem res = create_node("range", NodeItem::type(type));
res.set_input("in", val);
NodeItem res = create_node("range", type);
res.set_input("in", value);
res.set_input("inlow", from_min);
res.set_input("inhigh", from_max);
res.set_input("outlow", to_min);
res.set_input("outhigh", to_max);
res.set_input("doclamp", value(bool(map_range->clamp)));
res.set_input("doclamp", val(bool(map_range->clamp)));
return res;
}

View File

@ -14,7 +14,7 @@ NodeItem MathNodeParser::compute()
NodeItem res = empty();
/* Single operand operations */
NodeItem x = get_input_value(0, NodeItem::Type::Empty);
NodeItem x = get_input_value(0, NodeItem::Type::Any);
switch (op) {
case NODE_MATH_SINE:
res = x.sin();
@ -35,7 +35,7 @@ NodeItem MathNodeParser::compute()
res = x.atan();
break;
case NODE_MATH_ROUND:
res = (x + value(0.5f)).floor();
res = (x + val(0.5f)).floor();
break;
case NODE_MATH_ABSOLUTE:
res = x.abs();
@ -47,13 +47,13 @@ NodeItem MathNodeParser::compute()
res = x.ceil();
break;
case NODE_MATH_FRACTION:
res = x % value(1.0f);
res = x % val(1.0f);
break;
case NODE_MATH_SQRT:
res = x.sqrt();
break;
case NODE_MATH_INV_SQRT:
res = value(1.0f) / x.sqrt();
res = val(1.0f) / x.sqrt();
break;
case NODE_MATH_SIGN:
res = x.sign();
@ -62,10 +62,10 @@ NodeItem MathNodeParser::compute()
res = x.exp();
break;
case NODE_MATH_RADIANS:
res = x * value(float(M_PI) / 180.0f);
res = x * val(float(M_PI) / 180.0f);
break;
case NODE_MATH_DEGREES:
res = x * value(180.0f * float(M_1_PI));
res = x * val(180.0f * float(M_1_PI));
break;
case NODE_MATH_SINH:
res = x.sinh();
@ -82,7 +82,7 @@ NodeItem MathNodeParser::compute()
default: {
/* 2-operand operations */
NodeItem y = get_input_value(1, NodeItem::Type::Empty);
NodeItem y = get_input_value(1, NodeItem::Type::Any);
switch (op) {
case NODE_MATH_ADD:
res = x + y;
@ -109,10 +109,10 @@ NodeItem MathNodeParser::compute()
res = x.max(y);
break;
case NODE_MATH_LESS_THAN:
res = x.if_else(NodeItem::CompareOp::Less, y, value(1.0f), value(0.0f));
res = x.if_else(NodeItem::CompareOp::Less, y, val(1.0f), val(0.0f));
break;
case NODE_MATH_GREATER_THAN:
res = x.if_else(NodeItem::CompareOp::Greater, y, value(1.0f), value(0.0f));
res = x.if_else(NodeItem::CompareOp::Greater, y, val(1.0f), val(0.0f));
break;
case NODE_MATH_MODULO:
res = x % y;
@ -132,13 +132,13 @@ NodeItem MathNodeParser::compute()
default: {
/* 3-operand operations */
NodeItem z = get_input_value(2, NodeItem::Type::Empty);
NodeItem z = get_input_value(2, NodeItem::Type::Any);
switch (op) {
case NODE_MATH_WRAP:
CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op);
break;
case NODE_MATH_COMPARE:
res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), value(1.0f), value(0.0f));
res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), val(1.0f), val(0.0f));
break;
case NODE_MATH_MULTIPLY_ADD:
res = x * y + z;

View File

@ -0,0 +1,46 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem MixShaderNodeParser::compute()
{
NodeItem res = empty();
switch (shader_type_) {
case NodeItem::Type::BSDF:
case NodeItem::Type::EDF: {
NodeItem fac = get_input_value(0, NodeItem::Type::Float);
NodeItem shader1 = get_input_shader(1, shader_type_);
NodeItem shader2 = get_input_shader(2, shader_type_);
if (shader1 && !shader2) {
res = shader1 * (val(1.0f) - fac);
}
else if (!shader1 && shader2) {
res = shader2 * fac;
}
else if (shader1 && shader2) {
res = create_node("mix", shader_type_);
res.set_input("fg", shader1);
res.set_input("bg", shader2);
res.set_input("mix", fac);
}
break;
}
case NodeItem::Type::SurfaceShader: {
res = get_input_shader(1, NodeItem::Type::SurfaceShader);
if (!res) {
res = get_input_shader(2, NodeItem::Type::SurfaceShader);
}
break;
}
default:
BLI_assert_unreachable();
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -12,6 +12,91 @@ namespace blender::nodes::materialx {
NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
NodeItem::Type NodeItem::type(const std::string &type_str)
{
if (type_str == "string") {
return Type::String;
}
if (type_str == "filename") {
return Type::Filename;
}
if (type_str == "boolean") {
return Type::Bool;
}
if (type_str == "integer") {
return Type::Integer;
}
if (type_str == "float") {
return Type::Float;
}
if (type_str == "vector2") {
return Type::Vector2;
}
if (type_str == "vector3") {
return Type::Vector3;
}
if (type_str == "vector4") {
return Type::Vector4;
}
if (type_str == "color3") {
return Type::Color3;
}
if (type_str == "color4") {
return Type::Color4;
}
if (type_str == "BSDF") {
return Type::BSDF;
}
if (type_str == "EDF") {
return Type::EDF;
}
if (type_str == "surfaceshader") {
return Type::SurfaceShader;
}
if (type_str == "material") {
return Type::Material;
}
BLI_assert_unreachable();
return Type::Empty;
}
std::string NodeItem::type(Type type)
{
switch (type) {
case Type::String:
return "string";
case Type::Filename:
return "filename";
case Type::Bool:
return "boolean";
case Type::Integer:
return "integer";
case Type::Float:
return "float";
case Type::Vector2:
return "vector2";
case Type::Vector3:
return "vector3";
case Type::Vector4:
return "vector4";
case Type::Color3:
return "color3";
case Type::Color4:
return "color4";
case Type::BSDF:
return "BSDF";
case Type::EDF:
return "EDF";
case Type::SurfaceShader:
return "surfaceshader";
case Type::Material:
return "material";
default:
BLI_assert_unreachable();
}
return "";
}
NodeItem::operator bool() const
{
return value || node;
@ -19,6 +104,21 @@ NodeItem::operator bool() const
NodeItem NodeItem::operator+(const NodeItem &other) const
{
Type type = this->type();
if (ELEM(type, Type::BSDF, Type::EDF)) {
/* Special case: add BSDF/EDF shaders */
NodeItem res = empty();
if (other.type() == type) {
res = create_node("add", type);
res.set_input("in1", *this);
res.set_input("in2", other);
}
else {
BLI_assert_unreachable();
}
return res;
}
return arithmetic(other, "add", [](float a, float b) { return a + b; });
}
@ -34,6 +134,22 @@ NodeItem NodeItem::operator-() const
NodeItem NodeItem::operator*(const NodeItem &other) const
{
Type type = this->type();
if (ELEM(type, Type::BSDF, Type::EDF)) {
/* Special case: multiple BSDF/EDF shader by Float or Color3 */
NodeItem res = empty();
Type other_type = other.type();
if (ELEM(other_type, Type::Float, Type::Color3)) {
res = create_node("multiply", type);
res.set_input("in1", *this);
res.set_input("in2", other);
}
else {
BLI_assert_unreachable();
}
return res;
}
return arithmetic(other, "multiply", [](float a, float b) { return a * b; });
}
@ -70,7 +186,7 @@ bool NodeItem::operator==(const NodeItem &other) const
NodeItem item1 = *this;
NodeItem item2 = other;
Type to_type = adjust_types(item1, item2);
Type to_type = cast_types(item1, item2);
if (to_type == Type::Empty) {
return false;
}
@ -111,9 +227,8 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const
{
NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; });
if (d.value) {
Type mx_type = d.type();
float f = 0.0f;
switch (mx_type) {
switch (d.type()) {
case Type::Float: {
f = value->asA<float>();
break;
@ -239,7 +354,7 @@ NodeItem NodeItem::exp() const
NodeItem NodeItem::extract(const int index) const
{
NodeItem res = empty();
res.node = graph_->addNode("extract", MaterialX::EMPTY_STRING, "float");
res = create_node("extract", Type::Float);
res.set_input("in", *this);
res.set_input("index", val(index));
return res;
@ -248,10 +363,14 @@ NodeItem NodeItem::extract(const int index) const
NodeItem NodeItem::convert(Type to_type) const
{
Type from_type = type();
if (from_type == to_type) {
if (from_type == Type::Empty || from_type == to_type || to_type == Type::Any) {
return *this;
}
if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) {
CLOG_WARN(LOG_MATERIALX_SHADER,
"Cannot convert: %s -> %s",
type(from_type).c_str(),
type(to_type).c_str());
return empty();
}
@ -419,7 +538,7 @@ NodeItem NodeItem::convert(Type to_type) const
}
}
else {
res.node = graph_->addNode("convert", MaterialX::EMPTY_STRING, type(to_type));
res = create_node("convert", to_type);
res.set_input("in", *this);
}
return res;
@ -448,24 +567,24 @@ NodeItem NodeItem::if_else(CompareOp op,
auto item1 = if_val;
auto item2 = else_val;
Type to_type = adjust_types(item1, item2);
Type to_type = cast_types(item1, item2);
if (to_type == Type::Empty) {
return res;
}
std::function<bool(float, float)> func = nullptr;
std::string mx_category;
std::string category;
switch (op) {
case CompareOp::Greater:
mx_category = "ifgreater";
category = "ifgreater";
func = [](float a, float b) { return a > b; };
break;
case CompareOp::GreaterEq:
mx_category = "ifgreatereq";
category = "ifgreatereq";
func = [](float a, float b) { return a >= b; };
break;
case CompareOp::Eq:
mx_category = "ifequal";
category = "ifequal";
func = [](float a, float b) { return a == b; };
break;
default:
@ -476,7 +595,7 @@ NodeItem NodeItem::if_else(CompareOp op,
res = func(value->asA<float>(), other.value->asA<float>()) ? item1 : item2;
}
else {
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(to_type));
res = create_node(category, to_type);
res.set_input("value1", *this);
res.set_input("value2", other);
res.set_input("in1", item1);
@ -502,127 +621,81 @@ NodeItem::Type NodeItem::type() const
return Type::Empty;
}
void NodeItem::set_input(const std::string &name,
const NodeItem &item,
const std::string &output_name)
NodeItem NodeItem::create_node(const std::string &category, NodeItem::Type type) const
{
std::string type_str = this->type(type);
CLOG_INFO(LOG_MATERIALX_SHADER, 2, "<%s type=%s>", category.c_str(), type_str.c_str());
NodeItem res = empty();
res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type_str);
return res;
}
void NodeItem::set_input(const std::string &in_name, const NodeItem &item)
{
if (item.value) {
Type item_type = item.type();
std::string mx_type = type(item_type);
switch (item_type) {
case Type::String:
set_input(name, item.value->asA<std::string>(), mx_type);
set_input(in_name, item.value->asA<std::string>(), item_type);
break;
case Type::Bool:
set_input(name, item.value->asA<bool>(), mx_type);
set_input(in_name, item.value->asA<bool>(), item_type);
break;
case Type::Integer:
set_input(name, item.value->asA<int>(), mx_type);
set_input(in_name, item.value->asA<int>(), item_type);
break;
case Type::Float:
set_input(name, item.value->asA<float>(), mx_type);
set_input(in_name, item.value->asA<float>(), item_type);
break;
case Type::Vector2:
set_input(name, item.value->asA<MaterialX::Vector2>(), mx_type);
set_input(in_name, item.value->asA<MaterialX::Vector2>(), item_type);
break;
case Type::Vector3:
set_input(name, item.value->asA<MaterialX::Vector3>(), mx_type);
set_input(in_name, item.value->asA<MaterialX::Vector3>(), item_type);
break;
case Type::Vector4:
set_input(name, item.value->asA<MaterialX::Vector4>(), mx_type);
set_input(in_name, item.value->asA<MaterialX::Vector4>(), item_type);
break;
case Type::Color3:
set_input(name, item.value->asA<MaterialX::Color3>(), mx_type);
set_input(in_name, item.value->asA<MaterialX::Color3>(), item_type);
break;
case Type::Color4:
set_input(name, item.value->asA<MaterialX::Color4>(), mx_type);
set_input(in_name, item.value->asA<MaterialX::Color4>(), item_type);
break;
default:
BLI_assert_unreachable();
}
}
else if (item.node) {
node->setConnectedNode(name, item.node);
if (output_name != "") {
node->setConnectedOutput(name, item.node->getOutput(output_name));
}
node->setConnectedNode(in_name, item.node);
}
else {
CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", 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,
const NodeItem &item,
const std::string &out_name)
{
if (!item.node) {
BLI_assert_unreachable();
}
node->setConnectedNode(in_name, item.node);
node->setConnectedOutput(in_name, item.node->getOutput(out_name));
}
void NodeItem::add_output(const std::string &name, Type out_type)
{
node->addOutput(name, type(out_type));
}
NodeItem::Type NodeItem::type(const std::string &type_str)
{
if (type_str == "string") {
return Type::String;
}
if (type_str == "boolean") {
return Type::Bool;
}
if (type_str == "integer") {
return Type::Integer;
}
if (type_str == "float") {
return Type::Float;
}
if (type_str == "vector2") {
return Type::Vector2;
}
if (type_str == "vector3") {
return Type::Vector3;
}
if (type_str == "vector4") {
return Type::Vector4;
}
if (type_str == "color3") {
return Type::Color3;
}
if (type_str == "color4") {
return Type::Color4;
}
return Type::Other;
}
std::string NodeItem::type(Type type)
{
switch (type) {
case Type::String:
return "string";
case Type::Bool:
return "boolean";
case Type::Integer:
return "integer";
case Type::Float:
return "float";
case Type::Vector2:
return "vector2";
case Type::Vector3:
return "vector3";
case Type::Vector4:
return "vector4";
case Type::Color3:
return "color3";
case Type::Color4:
return "color4";
default:
BLI_assert_unreachable();
break;
}
return "";
}
bool NodeItem::is_arithmetic(Type type)
{
return type >= Type::Float;
return type >= Type::Float && type <= Type::Color4;
}
NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2)
{
Type t1 = item1.type();
Type t2 = item2.type();
@ -630,6 +703,8 @@ NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
return t1;
}
if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
CLOG_WARN(
LOG_MATERIALX_SHADER, "Can't adjust types: %s <-> %s", type(t1).c_str(), type(t2).c_str());
return Type::Empty;
}
if (t1 < t2) {
@ -697,7 +772,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(f
else {
/* TODO: Some of math functions (sin, cos, ...) doesn't work with Color types,
* we have to convert to Vector */
res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, this->type(type));
res = create_node(category, type);
res.set_input("in", *this);
}
return res;
@ -710,7 +785,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
NodeItem res = empty();
NodeItem item1 = *this;
NodeItem item2 = other;
Type to_type = adjust_types(item1, item2);
Type to_type = cast_types(item1, item2);
if (to_type == Type::Empty) {
return res;
}
@ -763,7 +838,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
}
}
else {
res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type(to_type));
res = create_node(category, to_type);
res.set_input("in1", item1);
res.set_input("in2", item2);
}

View File

@ -11,17 +11,29 @@ namespace blender::nodes::materialx {
class NodeItem {
public:
enum class Type {
Empty = 0,
Other, /* For MaterialX types like: surfaceshader, bsdf, edf, ...*/
Any = 0,
Empty,
/* Value types */
String,
Filename,
Bool,
Integer,
/* Block of arithmetic types. Ordered by type cast */
Float,
Vector2,
Vector3,
Vector4,
Color3,
Color4
Vector4,
Color4,
/* End of arithmetic types */
/* Shader types
* NOTE: There are only supported types */
BSDF,
EDF,
SurfaceShader,
Material,
};
enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq };
@ -36,6 +48,9 @@ class NodeItem {
NodeItem(MaterialX::GraphElement *graph);
~NodeItem() = default;
static Type type(const std::string &type_str);
static std::string type(Type type);
/* Operators */
operator bool() const;
NodeItem operator+(const NodeItem &other) const;
@ -48,9 +63,6 @@ class NodeItem {
bool operator==(const NodeItem &other) const;
bool operator!=(const NodeItem &other) const;
static Type type(const std::string &type_str);
static std::string type(Type type);
/* Math functions */
NodeItem abs() const;
NodeItem floor() const;
@ -86,18 +98,19 @@ class NodeItem {
NodeItem empty() const;
template<class T> NodeItem val(const T &data) const;
Type type() const;
NodeItem create_node(const std::string &category, NodeItem::Type type) const;
/* Functions to set input and output */
template<class T>
void set_input(const std::string &in_name, const T &value, const std::string &in_type);
void set_input(const std::string &in_name,
const NodeItem &item,
const std::string &out_name = "");
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_output(const std::string &in_name,
const NodeItem &item,
const std::string &out_name);
void add_output(const std::string &in_name, Type out_type);
private:
static bool is_arithmetic(Type type);
static Type adjust_types(NodeItem &item1, NodeItem &item2);
static Type cast_types(NodeItem &item1, NodeItem &item2);
bool is_arithmetic() const;
NodeItem arithmetic(const std::string &category, std::function<float(float)> func) const;
@ -114,9 +127,9 @@ template<class T> NodeItem NodeItem::val(const T &data) const
}
template<class T>
void NodeItem::set_input(const std::string &in_name, const T &value, const std::string &in_type)
void NodeItem::set_input(const std::string &in_name, const T &value, Type in_type)
{
node->setInputValue(in_name, value, in_type);
node->setInputValue(in_name, value, type(in_type));
}
} // namespace blender::nodes::materialx

View File

@ -22,48 +22,56 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph,
{
}
std::string NodeParser::node_name(const bNode *node, const bNodeSocket *socket_out)
NodeItem NodeParser::compute_full()
{
return MaterialX::createValidName(node->output_sockets().size() <= 1 ?
std::string(node->name) :
std::string(node->name) + "_" + socket_out->name);
}
NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type)
{
NodeItem res = empty();
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type);
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type);
NodeItem res = compute();
if (res.node) {
res.node->setName(node_name());
}
return res;
}
NodeItem NodeParser::get_input_default(const std::string &name)
std::string NodeParser::node_name()
{
return get_input_default(node_->input_by_identifier(name));
return MaterialX::createValidName(node_->output_sockets().size() <= 1 ?
std::string(node_->name) :
std::string(node_->name) + "_" + socket_out_->name);
}
NodeItem NodeParser::get_input_default(int index)
NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type)
{
return get_input_default(node_->input_socket(index));
return empty().create_node(category, type);
}
NodeItem NodeParser::get_input_link(const std::string &name)
NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type)
{
return get_input_link(node_->input_by_identifier(name));
return get_input_default(node_->input_by_identifier(name), to_type);
}
NodeItem NodeParser::get_input_link(int index)
NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type)
{
return get_input_link(node_->input_socket(index));
return get_input_default(node_->input_socket(index), to_type);
}
NodeItem NodeParser::get_input_value(const std::string &name, const NodeItem::Type type)
NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type)
{
return get_input_value(node_->input_by_identifier(name), type);
return get_input_link(node_->input_by_identifier(name), to_type);
}
NodeItem NodeParser::get_input_value(int index, const NodeItem::Type type)
NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type)
{
return get_input_value(node_->input_socket(index), type);
return get_input_link(node_->input_socket(index), to_type);
}
NodeItem NodeParser::get_input_value(const std::string &name, NodeItem::Type to_type)
{
return get_input_value(node_->input_by_identifier(name), to_type);
}
NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type)
{
return get_input_value(node_->input_socket(index), to_type);
}
NodeItem NodeParser::empty() const
@ -71,7 +79,7 @@ NodeItem NodeParser::empty() const
return NodeItem(graph_);
}
NodeItem NodeParser::get_input_default(const bNodeSocket &socket)
NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = empty();
switch (socket.type) {
@ -96,10 +104,10 @@ NodeItem NodeParser::get_input_default(const bNodeSocket &socket)
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type);
}
}
return res;
return res.convert(to_type);
}
NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = empty();
@ -119,22 +127,17 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
from_node = link->fromnode;
}
/* Checking if node was already computed */
res.node = graph_->getNode(node_name(from_node, link->fromsock));
if (res.node) {
return res;
}
/* Creating required NodeParser object */
std::unique_ptr<NodeParser> parser;
/* Computing from_node with required NodeParser object */
#define CASE_NODE_TYPE(type, T) \
case type: \
res = T(graph_, depsgraph_, material_, from_node, link->fromsock).compute_full(); \
parser = std::make_unique<T>(graph_, depsgraph_, material_, from_node, link->fromsock); \
break;
switch (from_node->typeinfo->type) {
CASE_NODE_TYPE(SH_NODE_BLACKBODY, BlackbodyNodeParser)
CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser)
CASE_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser)
CASE_NODE_TYPE(SH_NODE_CLAMP, ClampNodeParser)
CASE_NODE_TYPE(SH_NODE_COMBINE_COLOR, CombineColorNodeParser)
CASE_NODE_TYPE(SH_NODE_COMBXYZ, CombineXYZNodeParser)
@ -158,27 +161,137 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
from_node->name,
from_node->typeinfo->type);
}
if (!parser) {
return res;
}
/* Checking if node was already computed */
res.node = graph_->getNode(parser->node_name());
if (res.node) {
return res;
}
/* Computing */
res = parser->compute_full();
return res.convert(to_type);
}
NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = get_input_link(socket, to_type);
if (!res) {
res = get_input_default(socket, to_type);
}
return res;
}
NodeItem NodeParser::get_input_value(const bNodeSocket &socket, const NodeItem::Type type)
ShaderNodeParser::ShaderNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out,
NodeItem::Type shader_type)
: NodeParser(graph, depsgraph, material, node, socket_out), shader_type_(shader_type)
{
NodeItem res = get_input_link(socket);
if (!res) {
res = get_input_default(socket);
}
return type == NodeItem::Type::Empty ? res : res.convert(type);
}
NodeItem NodeParser::compute_full()
NodeItem ShaderNodeParser::compute_full()
{
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type);
CLOG_INFO(LOG_MATERIALX_SHADER,
1,
"%s [%d] - %s",
node_->name,
node_->typeinfo->type,
NodeItem::type(shader_type_).c_str());
NodeItem res = compute();
if (res.node) {
res.node->setName(node_name(node_, socket_out_));
res.node->setName(node_name());
}
return res;
}
std::string ShaderNodeParser::node_name()
{
std::string name = NodeParser::node_name();
if (shader_type_ != NodeItem::Type::SurfaceShader) {
name += "_" + NodeItem::type(shader_type_);
}
return name;
}
NodeItem ShaderNodeParser::get_input_shader(const std::string &name, NodeItem::Type shader_type)
{
return get_input_shader(node_->input_by_identifier(name), shader_type);
}
NodeItem ShaderNodeParser::get_input_shader(int index, NodeItem::Type shader_type)
{
return get_input_shader(node_->input_socket(index), shader_type);
}
NodeItem ShaderNodeParser::get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type)
{
NodeItem res = empty();
const bNodeLink *link = socket.link;
if (!(link && link->is_used())) {
return res;
}
const bNode *from_node = link->fromnode;
/* Passing NODE_REROUTE nodes */
while (from_node->type == NODE_REROUTE) {
link = from_node->input_socket(0).link;
if (!(link && link->is_used())) {
return res;
}
from_node = link->fromnode;
}
/* Creating required ShaderNodeParser object */
std::unique_ptr<ShaderNodeParser> parser;
#define CASE_SHADER_NODE_TYPE(type, T) \
case type: \
parser = std::make_unique<T>( \
graph_, depsgraph_, material_, from_node, link->fromsock, shader_type); \
break;
switch (from_node->typeinfo->type) {
CASE_SHADER_NODE_TYPE(SH_NODE_ADD_SHADER, AddShaderNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_DIFFUSE, BSDFDiffuseNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLASS, BSDFGlassNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLOSSY, BSDFGlossyNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_REFRACTION, BSDFRefractionNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_SHEEN, BSDFSheenNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TOON, BSDFToonNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSLUCENT, BSDFTranslucentNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSPARENT, BSDFTransparentNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_EMISSION, EmissionNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_MIX_SHADER, MixShaderNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_SUBSURFACE_SCATTERING, SubsurfaceScatteringNodeParser)
default:
CLOG_WARN(LOG_MATERIALX_SHADER,
"Unsupported node: %s [%d]",
from_node->name,
from_node->typeinfo->type);
}
if (!parser) {
return res;
}
/* Checking if node was already computed */
res.node = graph_->getNode(parser->node_name());
if (res.node) {
return res;
}
/* Computing */
res = parser->compute_full();
return res;
}
} // namespace blender::nodes::materialx

View File

@ -31,56 +31,96 @@ class NodeParser {
virtual NodeItem compute() = 0;
protected:
static std::string node_name(const bNode *node, const bNodeSocket *socket_out);
NodeItem create_node(const std::string &mx_category, const std::string &mx_type);
NodeItem get_input_default(const std::string &name);
NodeItem get_input_default(int index);
NodeItem get_input_link(const std::string &name);
NodeItem get_input_link(int index);
NodeItem get_input_value(const std::string &name,
const NodeItem::Type type);
NodeItem get_input_value(int index, const NodeItem::Type type);
virtual NodeItem compute_full();
virtual std::string node_name();
NodeItem create_node(const std::string &category, NodeItem::Type 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_link(const std::string &name, NodeItem::Type to_type);
NodeItem get_input_link(int index, NodeItem::Type to_type);
NodeItem get_input_value(const std::string &name, NodeItem::Type to_type);
NodeItem get_input_value(int index, NodeItem::Type to_type);
NodeItem empty() const;
template<class T> NodeItem value(const T &data) const;
template<class T> NodeItem val(const T &data) const;
private:
NodeItem get_input_default(const bNodeSocket &socket);
NodeItem get_input_link(const bNodeSocket &socket);
NodeItem get_input_value(const bNodeSocket &socket,
const NodeItem::Type type);
NodeItem compute_full();
NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type);
NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type);
NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type);
};
template<class T> NodeItem NodeParser::value(const T &data) const
class ShaderNodeParser : public NodeParser {
protected:
NodeItem::Type shader_type_;
public:
ShaderNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out,
NodeItem::Type shader_type);
protected:
NodeItem compute_full() override;
std::string node_name() override;
NodeItem get_input_shader(const std::string &name, NodeItem::Type shader_type);
NodeItem get_input_shader(int index, NodeItem::Type shader_type);
private:
NodeItem get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type);
};
template<class T> NodeItem NodeParser::val(const T &data) const
{
return empty().val(data);
}
#define DECLARE_PARSER(T) \
#define DECLARE_NODE_PARSER(T) \
class T : public NodeParser { \
public: \
using NodeParser::NodeParser; \
NodeItem compute() override; \
};
DECLARE_PARSER(BlackbodyNodeParser)
DECLARE_PARSER(BrightContrastNodeParser)
DECLARE_PARSER(BSDFPrincipledNodeParser)
DECLARE_PARSER(ClampNodeParser)
DECLARE_PARSER(CombineColorNodeParser)
DECLARE_PARSER(CombineXYZNodeParser)
DECLARE_PARSER(HueSatValNodeParser)
DECLARE_PARSER(InvertNodeParser)
DECLARE_PARSER(MapRangeNodeParser)
DECLARE_PARSER(MathNodeParser)
DECLARE_PARSER(MixRGBNodeParser)
DECLARE_PARSER(NormalMapNodeParser)
DECLARE_PARSER(SeparateColorNodeParser)
DECLARE_PARSER(SeparateXYZNodeParser)
DECLARE_PARSER(TexCheckerNodeParser)
DECLARE_PARSER(TexEnvironmentNodeParser)
DECLARE_PARSER(TexImageNodeParser)
DECLARE_PARSER(TexNoiseNodeParser)
DECLARE_PARSER(VectorMathNodeParser)
#define DECLARE_SHADER_NODE_PARSER(T) \
class T : public ShaderNodeParser { \
public: \
using ShaderNodeParser::ShaderNodeParser; \
NodeItem compute() override; \
};
DECLARE_NODE_PARSER(BlackbodyNodeParser)
DECLARE_NODE_PARSER(BrightContrastNodeParser)
DECLARE_NODE_PARSER(ClampNodeParser)
DECLARE_NODE_PARSER(CombineColorNodeParser)
DECLARE_NODE_PARSER(CombineXYZNodeParser)
DECLARE_NODE_PARSER(HueSatValNodeParser)
DECLARE_NODE_PARSER(InvertNodeParser)
DECLARE_NODE_PARSER(MapRangeNodeParser)
DECLARE_NODE_PARSER(MathNodeParser)
DECLARE_NODE_PARSER(MixRGBNodeParser)
DECLARE_NODE_PARSER(NormalMapNodeParser)
DECLARE_NODE_PARSER(SeparateColorNodeParser)
DECLARE_NODE_PARSER(SeparateXYZNodeParser)
DECLARE_NODE_PARSER(TexCheckerNodeParser)
DECLARE_NODE_PARSER(TexEnvironmentNodeParser)
DECLARE_NODE_PARSER(TexImageNodeParser)
DECLARE_NODE_PARSER(TexNoiseNodeParser)
DECLARE_NODE_PARSER(VectorMathNodeParser)
DECLARE_SHADER_NODE_PARSER(AddShaderNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFDiffuseNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFGlassNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFGlossyNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFPrincipledNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFRefractionNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFSheenNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFToonNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFTranslucentNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFTransparentNodeParser)
DECLARE_SHADER_NODE_PARSER(EmissionNodeParser)
DECLARE_SHADER_NODE_PARSER(MixShaderNodeParser)
DECLARE_SHADER_NODE_PARSER(SubsurfaceScatteringNodeParser)
} // namespace blender::nodes::materialx

View File

@ -14,19 +14,19 @@ NodeItem NormalMapNodeParser::compute()
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
NodeItem strength = get_input_value("Strength", NodeItem::Type::Float);
NodeItem res = create_node("normalmap", "vector3");
NodeItem res = create_node("normalmap", NodeItem::Type::Vector3);
res.set_input("in", color);
res.set_input("scale", strength);
switch (normal_map_node->space) {
case SHD_SPACE_TANGENT:
res.set_input("space", value(std::string("tangent")));
res.set_input("space", val(std::string("tangent")));
break;
case SHD_SPACE_OBJECT:
res.set_input("space", value(std::string("tangent")));
res.set_input("space", val(std::string("tangent")));
break;
default:
res.set_input("space", value(default_space));
res.set_input("space", val(default_space));
CLOG_WARN(LOG_MATERIALX_SHADER,
"Ignoring unsupported Space: %d %s (%d), %s will be used",
normal_map_node->space,

View File

@ -9,50 +9,62 @@ OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *grap
const Depsgraph *depsgraph,
const Material *material,
const bNode *node)
: NodeParser(graph, depsgraph, material, node, nullptr)
: ShaderNodeParser(graph, depsgraph, material, node, nullptr, NodeItem::Type::Material)
{
}
NodeItem OutputMaterialNodeParser::compute()
{
return empty();
}
NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name)
{
NodeItem surface = empty();
if (node_) {
surface = get_input_link(socket_name);
NodeItem bsdf = get_input_shader("Surface", NodeItem::Type::BSDF);
NodeItem edf = get_input_shader("Surface", NodeItem::Type::EDF);
if (bsdf || edf) {
surface = create_node("surface", NodeItem::Type::SurfaceShader);
if (bsdf) {
surface.set_input("bsdf", bsdf);
}
if (edf) {
surface.set_input("edf", edf);
}
}
else {
surface = get_input_shader("Surface", NodeItem::Type::SurfaceShader);
}
}
else {
surface = create_node("standard_surface", "surfaceshader");
surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
surface = create_node("standard_surface", NodeItem::Type::SurfaceShader);
surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
}
NodeItem res = create_node("surfacematerial", "material");
res.node->setName(node_name(node_, nullptr));
NodeItem res = create_node("surfacematerial", NodeItem::Type::Material);
res.set_input("surfaceshader", surface);
return res;
}
NodeItem OutputMaterialNodeParser::compute_default()
{
NodeItem surface = create_node("standard_surface", "surfaceshader");
NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader);
surface.set_input("base_color",
value(MaterialX::Color3(material_->r, material_->g, material_->b)));
surface.set_input("diffuse_roughness", value(material_->roughness));
val(MaterialX::Color3(material_->r, material_->g, material_->b)));
surface.set_input("diffuse_roughness", val(material_->roughness));
if (material_->metallic > 0.0f) {
surface.set_input("metalness", value(material_->metallic));
surface.set_input("metalness", val(material_->metallic));
}
if (material_->spec) {
surface.set_input("specular", value(material_->spec));
surface.set_input("specular_color", value(material_->spec));
surface.set_input("specular_roughness", value(material_->roughness));
surface.set_input("specular", val(material_->spec));
surface.set_input("specular_color", val(material_->spec));
surface.set_input("specular_roughness", val(material_->roughness));
}
NodeItem res = create_node("surfacematerial", "material");
NodeItem res = create_node("surfacematerial", NodeItem::Type::Material);
res.node->setName("Material_Default");
res.set_input("surfaceshader", surface);
return res;
}
std::string OutputMaterialNodeParser::node_name()
{
return NodeParser::node_name();
}
} // namespace blender::nodes::materialx

View File

@ -8,15 +8,19 @@
namespace blender::nodes::materialx {
class OutputMaterialNodeParser : public NodeParser {
class OutputMaterialNodeParser : public ShaderNodeParser {
public:
OutputMaterialNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node);
NodeItem compute() override;
NodeItem compute(const std::string &socket_name);
using ShaderNodeParser::compute_full;
NodeItem compute_default();
protected:
std::string node_name() override;
};
} // namespace blender::nodes::materialx

View File

@ -18,12 +18,12 @@ NodeItem SeparateColorNodeParser::compute()
case NODE_COMBSEP_COLOR_RGB:
break;
case NODE_COMBSEP_COLOR_HSV:
convert = create_node("rgbtohsv", "color3");
convert = create_node("rgbtohsv", NodeItem::Type::Color3);
convert.set_input("in", color);
break;
case NODE_COMBSEP_COLOR_HSL:
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported color model, using HSV instead: %d", mode);
convert = create_node("rgbtohsv", "color3");
convert = create_node("rgbtohsv", NodeItem::Type::Color3);
convert.set_input("in", color);
break;
default:
@ -44,7 +44,7 @@ NodeItem CombineColorNodeParser::compute()
NodeItem blue = get_input_value("Blue", NodeItem::Type::Float);
NodeItem convert = empty();
NodeItem combine = create_node("combine3", "color3");
NodeItem combine = create_node("combine3", NodeItem::Type::Color3);
combine.set_input("in1", red);
combine.set_input("in2", green);
combine.set_input("in3", blue);
@ -53,12 +53,12 @@ NodeItem CombineColorNodeParser::compute()
case NODE_COMBSEP_COLOR_RGB:
break;
case NODE_COMBSEP_COLOR_HSV:
convert = create_node("hsvtorgb", "color3");
convert = create_node("hsvtorgb", NodeItem::Type::Color3);
convert.set_input("in", combine);
break;
case NODE_COMBSEP_COLOR_HSL:
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported color model, using HSV instead: %d", mode);
convert = create_node("hsvtorgb", "color3");
convert = create_node("hsvtorgb", NodeItem::Type::Color3);
convert.set_input("in", combine);
break;
default:

View File

@ -18,7 +18,7 @@ NodeItem CombineXYZNodeParser::compute()
NodeItem x = get_input_value("X", NodeItem::Type::Float);
NodeItem y = get_input_value("Y", NodeItem::Type::Float);
NodeItem z = get_input_value("Z", NodeItem::Type::Float);
NodeItem res = create_node("combine3", "vector3");
NodeItem res = create_node("combine3", NodeItem::Type::Vector3);
res.set_input("in1", x);
res.set_input("in2", y);
res.set_input("in3", z);

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem SubsurfaceScatteringNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -8,36 +8,21 @@ namespace blender::nodes::materialx {
NodeItem TexCheckerNodeParser::compute()
{
NodeItem vector = get_input_link("Vector");
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2);
NodeItem color1 = get_input_value("Color1", NodeItem::Type::Color3);
NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3);
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
if (!vector) {
vector = create_node("texcoord", "vector2");
vector = create_node("texcoord", NodeItem::Type::Vector2);
}
vector = vector * scale;
NodeItem separate = create_node("separate2", "multioutput");
separate.set_input("in", vector);
separate.add_output("outx", NodeItem::Type::Float);
separate.add_output("outy", NodeItem::Type::Float);
NodeItem modulo_x = create_node("modulo", "float");
modulo_x.set_input("in1", separate, "outx");
modulo_x.set_input("in2", value(2.0f));
NodeItem modulo_y = create_node("modulo", "float");
modulo_y.set_input("in1", separate, "outy");
modulo_y.set_input("in2", value(2.0f));
NodeItem ifequal = (modulo_x.floor() + modulo_y.floor())
.if_else(NodeItem::CompareOp::Eq, value(1.0f), value(0.0f), value(1.0f));
NodeItem res = create_node("mix", "color3");
res.set_input("bg", color1);
res.set_input("fg", color2);
res.set_input("mix", ifequal);
vector = (vector * scale) % val(2.0f);
NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor())
.if_else(NodeItem::CompareOp::Eq, val(1.0f), val(1.0f), val(0.0f));
NodeItem res = create_node("mix", NodeItem::Type::Color3);
res.set_input("fg", color1);
res.set_input("bg", color2);
res.set_input("mix", mix);
return res;
}

View File

@ -23,9 +23,9 @@ NodeItem TexEnvironmentNodeParser::compute()
image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser);
#endif
NodeItem texcoord = create_node("texcoord", "vector2");
NodeItem res = create_node("image", "color3");
res.set_input("file", image_path, "filename");
NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2);
NodeItem res = create_node("image", NodeItem::Type::Color3);
res.set_input("file", image_path, NodeItem::Type::Filename);
res.set_input("texcoord", texcoord);
return res;
}

View File

@ -23,9 +23,9 @@ NodeItem TexImageNodeParser::compute()
image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser);
#endif
NodeItem texcoord = create_node("texcoord", "vector2");
NodeItem res = create_node("image", "color3");
res.set_input("file", image_path, "filename");
NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2);
NodeItem res = create_node("image", NodeItem::Type::Color3);
res.set_input("file", image_path, NodeItem::Type::Filename);
res.set_input("texcoord", texcoord);
return res;
}

View File

@ -13,13 +13,13 @@ NodeItem TexNoiseNodeParser::compute()
NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float);
if (detail.value && detail.type() == NodeItem::Type::Float) {
detail = value(int(detail.value->asA<float>()));
detail = val(int(detail.value->asA<float>()));
}
NodeItem position = create_node("position", "vector3");
NodeItem position = create_node("position", NodeItem::Type::Vector3);
position = position * scale;
NodeItem res = create_node("fractal3d", "color3");
NodeItem res = create_node("fractal3d", NodeItem::Type::Color3);
res.set_input("position", position);
res.set_input("octaves", detail);
res.set_input("lacunarity", lacunarity);

View File

@ -14,7 +14,7 @@ NodeItem VectorMathNodeParser::compute()
NodeItem res = empty();
/* Single operand operations */
NodeItem x = get_input_value(0, NodeItem::Type::Empty);
NodeItem x = get_input_value(0, NodeItem::Type::Any);
switch (op) {
case NODE_VECTOR_MATH_SINE:
res = x.sin();
@ -35,7 +35,7 @@ NodeItem VectorMathNodeParser::compute()
res = x.ceil();
break;
case NODE_VECTOR_MATH_FRACTION:
res = x % value(1.0f);
res = x % val(1.0f);
break;
case NODE_VECTOR_MATH_LENGTH:
CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op);
@ -46,7 +46,7 @@ NodeItem VectorMathNodeParser::compute()
default: {
/* 2-operand operations */
NodeItem y = get_input_value(1, NodeItem::Type::Empty);
NodeItem y = get_input_value(1, NodeItem::Type::Any);
switch (op) {
case NODE_VECTOR_MATH_ADD:
res = x + y;
@ -93,7 +93,7 @@ NodeItem VectorMathNodeParser::compute()
default: {
/* 3-operand operations */
NodeItem z = get_input_value(2, NodeItem::Type::Empty);
NodeItem z = get_input_value(2, NodeItem::Type::Any);
switch (op) {
case NODE_VECTOR_MATH_MULTIPLY_ADD:
res = x * y + z;