1
1
Fork 0

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,
BogdanNagirniak marked this conversation as resolved Outdated

Maybe rename to Boolean, as we use full names for other types?

Maybe rename to Boolean, as we use full names for other types?
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();