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();
@ -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;