From 11faad2771dc63688ad892f1f0513671d6991b5a Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 29 Aug 2023 21:45:43 +0300 Subject: [PATCH 1/9] Continuing arithmetic implementation for NodeItem --- source/blender/nodes/shader/CMakeLists.txt | 2 + .../shader/materialx/nodes/bsdf_principled.cc | 14 +- .../nodes/shader/materialx/nodes/math.cc | 2 +- .../nodes/shader/materialx/nodes/mix_rgb.cc | 2 +- .../shader/materialx/nodes/node_parser.cc | 145 +++++++++++++++++- .../shader/materialx/nodes/node_parser.h | 21 ++- .../shader/materialx/nodes/output_material.cc | 2 +- 7 files changed, 173 insertions(+), 15 deletions(-) diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 064f203db349..f33931df645e 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -152,11 +152,13 @@ if(WITH_MATERIALX) materialx/nodes/invert.cc materialx/nodes/math.cc materialx/nodes/mix_rgb.cc + #materialx/nodes/node_item.cc materialx/nodes/node_parser.cc materialx/nodes/output_material.cc materialx/nodes/tex_image.cc materialx/material.h + #materialx/nodes/node_item.h materialx/nodes/node_parser.h ) endif() diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 5dee4cc40d61..10c19cb4f7d3 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -30,8 +30,8 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem base_color = get_input_value("Base Color"); NodeItem subsurface = get_input_value("Subsurface"); - NodeItem subsurface_radius = empty_value(); - NodeItem subsurface_color = empty_value(); + NodeItem subsurface_radius = empty(); + NodeItem subsurface_color = empty(); if (enabled(subsurface)) { subsurface_radius = get_input_value("Subsurface Radius"); subsurface_color = get_input_value("Subsurface Color"); @@ -42,8 +42,8 @@ NodeItem BSDFPrincipledNodeParser::compute() // NodeItem specular_tint = get_input_value("Specular Tint"); NodeItem roughness = get_input_value("Roughness"); - NodeItem anisotropic = empty_value(); - NodeItem anisotropic_rotation = empty_value(); + NodeItem anisotropic = empty(); + NodeItem anisotropic_rotation = empty(); if (enabled(metallic)) { /* TODO: use Specular Tint input */ anisotropic = get_input_value("Anisotropic"); @@ -54,12 +54,12 @@ NodeItem BSDFPrincipledNodeParser::compute() } NodeItem sheen = get_input_value("Sheen"); - // sheen_tint = empty_value(); + // sheen_tint = empty(); // if enabled(sheen): // sheen_tint = get_input_value("Sheen Tint"); NodeItem clearcoat = get_input_value("Clearcoat"); - NodeItem clearcoat_roughness = empty_value(); + NodeItem clearcoat_roughness = empty(); if (enabled(clearcoat)) { clearcoat_roughness = get_input_value("Clearcoat Roughness"); } @@ -67,7 +67,7 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem ior = get_input_value("IOR"); NodeItem transmission = get_input_value("Transmission"); - NodeItem transmission_roughness = empty_value(); + NodeItem transmission_roughness = empty(); if (enabled(transmission)) { transmission_roughness = get_input_value("Transmission Roughness"); } diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index 3cee80450a6a..ad5901d367c6 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -9,7 +9,7 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { /* TODO: implement */ - return empty_value(); + return empty(); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc index 34cfad6891e5..c06cf322a0f3 100644 --- a/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc +++ b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc @@ -9,7 +9,7 @@ namespace blender::nodes::materialx { NodeItem MixRGBNodeParser::compute() { /* TODO: implement */ - return empty_value(); + return empty(); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 3b65ec9bf3f6..179897324427 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -84,6 +84,17 @@ NodeItem NodeItem::operator/(const NodeItem &other) const return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); } +NodeItem NodeItem::operator%(const NodeItem &other) const +{ + return arithmetic( + other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmodf(a, b); }); +} + +NodeItem NodeItem::operator^(const NodeItem &other) const +{ + return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); }); +} + bool NodeItem::operator==(const NodeItem &other) const { if (node && node == other.node) { @@ -93,6 +104,21 @@ bool NodeItem::operator==(const NodeItem &other) const return false; } +NodeItem NodeItem::abs() const +{ + return arithmetic("absval", [](float a) { return std::fabsf(a); }); +} + +NodeItem NodeItem::floor() const +{ + return arithmetic("floor", [](float a) { return std::floorf(a); }); +} + +NodeItem NodeItem::ceil() const +{ + return arithmetic("ceil", [](float a) { return std::ceilf(a); }); +} + NodeItem NodeItem::min(const NodeItem &other) const { return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); @@ -103,11 +129,122 @@ NodeItem NodeItem::max(const NodeItem &other) const return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); } +NodeItem NodeItem::dot(const NodeItem &other) const +{ + NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); + if (d.value) { + std::string t = d.type(); + float f = 0.0f; + if (t == "float") { + f = value->asA(); + } + else if (t == "color3") { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + } + else if (t == "color4") { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + } + else if (t == "vector2") { + auto v = value->asA(); + f = v[0] + v[1]; + } + else if (t == "vector3") { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + } + else if (t == "vector4") { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + } + d.value = MaterialX::Value::createValue(f); + } + return d; +} + +NodeItem NodeItem::if_else(char condition, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const +{ + //def if_else(self, cond: str, other, if_value, else_value): + // if cond == '>': + // res = self._arithmetic_helper(other, 'ifgreater', lambda a, b: float(a > b)) + // elif cond == '>=': + // res = self._arithmetic_helper(other, 'ifgreatereq', lambda a, b: float(a >= b)) + // elif cond == '==': + // res = self._arithmetic_helper(other, 'ifequal', lambda a, b: float(a == b)) + // elif cond == '<': + // return self.node_item(other).if_else('>', self, else_value, if_value) + // elif cond == '<=': + // return self.node_item(other).if_else('>=', self, else_value, if_value) + // elif cond == '!=': + // return self.if_else('==', other, else_value, if_value) + // else: + // raise ValueError("Incorrect condition:", cond) + + // if isinstance(res.data, float): + // return if_value if res.data == 1.0 else else_value + // elif isinstance(res.data, tuple): + // return if_value if res.data[0] == 1.0 else else_value + // else: + // res.set_input('value1', if_value) + // res.set_input('value2', else_value) + // return res + return empty(); +} + NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const { return (val(1.0f) - *this) * a + *this * b; } +NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const +{ + return min(max_val).max(min_val); +} + +NodeItem NodeItem::clamp(float min_val, float max_val) const +{ + return clamp(val(min_val), val(max_val)); +} + +NodeItem NodeItem::sin() const +{ + return arithmetic("sin", [](float a) { return std::sinf(a); }); +} + +NodeItem NodeItem::cos() const +{ + return arithmetic("cos", [](float a) { return std::cosf(a); }); +} + +NodeItem NodeItem::tan() const +{ + return arithmetic("tan", [](float a) { return std::tanf(a); }); +} + +NodeItem NodeItem::asin() const +{ + return arithmetic("asin", [](float a) { return std::asinf(a); }); +} + +NodeItem NodeItem::acos() const +{ + return arithmetic("acos", [](float a) { return std::acosf(a); }); +} + +NodeItem NodeItem::atan() const +{ + return arithmetic("atan", [](float a) { return std::atanf(a); }); +} + +NodeItem NodeItem::log() const +{ + return arithmetic("ln", [](float a) { return std::logf(a); }); +} + NodeItem NodeItem::to_color3() const { std::string t = type(); @@ -337,7 +474,7 @@ NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type, bool accessory) { - NodeItem res = empty_value(); + NodeItem res = empty(); res.node = graph->addNode(mx_category, accessory ? MaterialX::EMPTY_STRING : MaterialX::createValidName(node->name), @@ -347,7 +484,7 @@ NodeItem NodeParser::create_node(const std::string &mx_category, NodeItem NodeParser::get_input_default(const std::string &name) { - NodeItem res = empty_value(); + NodeItem res = empty(); const bNodeSocket &socket = node->input_by_identifier(name); switch (socket.type) { @@ -374,7 +511,7 @@ NodeItem NodeParser::get_input_default(const std::string &name) NodeItem NodeParser::get_input_link(const std::string &name) { - NodeItem res = empty_value(); + NodeItem res = empty(); const bNodeLink *link = node->input_by_identifier(name).link; if (!(link && link->is_used())) { @@ -428,7 +565,7 @@ NodeItem NodeParser::get_input_value(const std::string &name) return res; } -NodeItem NodeParser::empty_value() +NodeItem NodeParser::empty() { return NodeItem(graph); } diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index d2604ff265b2..033184c0d139 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -38,11 +38,30 @@ class NodeItem { NodeItem operator-(const NodeItem &other) const; NodeItem operator*(const NodeItem &other) const; NodeItem operator/(const NodeItem &other) const; + NodeItem operator%(const NodeItem &other) const; + NodeItem operator^(const NodeItem &other) const; bool operator==(const NodeItem &other) const; + NodeItem abs() const; + NodeItem floor() const; + NodeItem ceil() const; NodeItem min(const NodeItem &other) const; NodeItem max(const NodeItem &other) const; + NodeItem dot(const NodeItem &other) const; + NodeItem if_else(char condition, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const; NodeItem blend(const NodeItem &a, const NodeItem &b) const; + NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const; + NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const; + NodeItem sin() const; + NodeItem cos() const; + NodeItem tan() const; + NodeItem asin() const; + NodeItem acos() const; + NodeItem atan() const; + NodeItem log() const; NodeItem to_color3() const; bool is_numeric() const; @@ -92,7 +111,7 @@ class NodeParser { NodeItem get_input_default(const std::string &name); NodeItem get_input_link(const std::string &name); NodeItem get_input_value(const std::string &name); - NodeItem empty_value(); + NodeItem empty(); }; #define DECLARE_PARSER(T) \ diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index dd44f7692ba9..94a106c40c03 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -8,7 +8,7 @@ namespace blender::nodes::materialx { NodeItem OutputMaterialNodeParser::compute() { - NodeItem node = empty_value(); + NodeItem node = empty(); NodeItem surface = get_input_link("Surface"); if (surface) { node = create_node("surfacematerial", "material"); -- 2.30.2 From eac5fee07de7eecb52ba32d7c476a2a8a3b4ae22 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Wed, 30 Aug 2023 12:23:33 +0300 Subject: [PATCH 2/9] Refactor: separated NodeItem and NodeParser to different files --- source/blender/nodes/shader/CMakeLists.txt | 4 +- .../nodes/shader/materialx/nodes/node_item.cc | 466 ++++++++++++++++++ .../nodes/shader/materialx/nodes/node_item.h | 87 ++++ .../shader/materialx/nodes/node_parser.cc | 454 ----------------- .../shader/materialx/nodes/node_parser.h | 78 +-- 5 files changed, 556 insertions(+), 533 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/node_item.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/node_item.h diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index f33931df645e..abbe0851ff55 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -152,13 +152,13 @@ if(WITH_MATERIALX) materialx/nodes/invert.cc materialx/nodes/math.cc materialx/nodes/mix_rgb.cc - #materialx/nodes/node_item.cc + materialx/nodes/node_item.cc materialx/nodes/node_parser.cc materialx/nodes/output_material.cc materialx/nodes/tex_image.cc materialx/material.h - #materialx/nodes/node_item.h + materialx/nodes/node_item.h materialx/nodes/node_parser.h ) endif() diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc new file mode 100644 index 000000000000..e1473399a78d --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -0,0 +1,466 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_item.h" + +#include "BLI_assert.h" +#include "BLI_utildefines.h" + +namespace blender::nodes::materialx { + +NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} + +NodeItem NodeItem::empty() const +{ + return NodeItem(graph_); +} + +void NodeItem::set_input(const std::string &name, const NodeItem &item) +{ + if (item.value) { + set_input(name, item.value); + } + else if (item.node) { + set_input(name, item.node); + } +} + +void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) +{ + std::string mx_type = value->getTypeString(); + if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); + } + else { + BLI_assert_unreachable(); + } +} + +void NodeItem::set_input(const std::string &name, const MaterialX::NodePtr node) +{ + this->node->setConnectedNode(name, node); +} + +NodeItem::operator bool() const +{ + return value || node; +} + +NodeItem NodeItem::operator+(const NodeItem &other) const +{ + return arithmetic(other, "add", [](float a, float b) { return a + b; }); +} + +NodeItem NodeItem::operator-(const NodeItem &other) const +{ + return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); +} + +NodeItem NodeItem::operator*(const NodeItem &other) const +{ + return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); +} + +NodeItem NodeItem::operator/(const NodeItem &other) const +{ + return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); +} + +NodeItem NodeItem::operator%(const NodeItem &other) const +{ + return arithmetic( + other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmodf(a, b); }); +} + +NodeItem NodeItem::operator^(const NodeItem &other) const +{ + return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); }); +} + +bool NodeItem::operator==(const NodeItem &other) const +{ + if (node && node == other.node) { + return true; + } + /* TODO: implement */ + return false; +} + +NodeItem NodeItem::abs() const +{ + return arithmetic("absval", [](float a) { return std::fabsf(a); }); +} + +NodeItem NodeItem::floor() const +{ + return arithmetic("floor", [](float a) { return std::floorf(a); }); +} + +NodeItem NodeItem::ceil() const +{ + return arithmetic("ceil", [](float a) { return std::ceilf(a); }); +} + +NodeItem NodeItem::min(const NodeItem &other) const +{ + return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); +} + +NodeItem NodeItem::max(const NodeItem &other) const +{ + return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); +} + +NodeItem NodeItem::dot(const NodeItem &other) const +{ + NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); + if (d.value) { + std::string t = d.type(); + float f = 0.0f; + if (t == "float") { + f = value->asA(); + } + else if (t == "color3") { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + } + else if (t == "color4") { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + } + else if (t == "vector2") { + auto v = value->asA(); + f = v[0] + v[1]; + } + else if (t == "vector3") { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + } + else if (t == "vector4") { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + } + d.value = MaterialX::Value::createValue(f); + } + return d; +} + +NodeItem NodeItem::if_else(char condition, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const +{ + //def if_else(self, cond: str, other, if_value, else_value): + // if cond == '>': + // res = self._arithmetic_helper(other, 'ifgreater', lambda a, b: float(a > b)) + // elif cond == '>=': + // res = self._arithmetic_helper(other, 'ifgreatereq', lambda a, b: float(a >= b)) + // elif cond == '==': + // res = self._arithmetic_helper(other, 'ifequal', lambda a, b: float(a == b)) + // elif cond == '<': + // return self.node_item(other).if_else('>', self, else_value, if_value) + // elif cond == '<=': + // return self.node_item(other).if_else('>=', self, else_value, if_value) + // elif cond == '!=': + // return self.if_else('==', other, else_value, if_value) + // else: + // raise ValueError("Incorrect condition:", cond) + + // if isinstance(res.data, float): + // return if_value if res.data == 1.0 else else_value + // elif isinstance(res.data, tuple): + // return if_value if res.data[0] == 1.0 else else_value + // else: + // res.set_input('value1', if_value) + // res.set_input('value2', else_value) + // return res + return empty(); +} + +NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const +{ + return (val(1.0f) - *this) * a + *this * b; +} + +NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const +{ + return min(max_val).max(min_val); +} + +NodeItem NodeItem::clamp(float min_val, float max_val) const +{ + return clamp(val(min_val), val(max_val)); +} + +NodeItem NodeItem::sin() const +{ + return arithmetic("sin", [](float a) { return std::sinf(a); }); +} + +NodeItem NodeItem::cos() const +{ + return arithmetic("cos", [](float a) { return std::cosf(a); }); +} + +NodeItem NodeItem::tan() const +{ + return arithmetic("tan", [](float a) { return std::tanf(a); }); +} + +NodeItem NodeItem::asin() const +{ + return arithmetic("asin", [](float a) { return std::asinf(a); }); +} + +NodeItem NodeItem::acos() const +{ + return arithmetic("acos", [](float a) { return std::acosf(a); }); +} + +NodeItem NodeItem::atan() const +{ + return arithmetic("atan", [](float a) { return std::atanf(a); }); +} + +NodeItem NodeItem::log() const +{ + return arithmetic("ln", [](float a) { return std::logf(a); }); +} + +NodeItem NodeItem::to_color3() const +{ + std::string t = type(); + NodeItem res = empty(); + if (value) { + MaterialX::Color3 c; + if (t == "float") { + float v = value->asA(); + c = {v, v, v}; + } + else if (t == "color3") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "color4") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "vector3") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "vector4") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else { + return res; + } + res.value = MaterialX::Value::createValue(c); + } + else if (node) { + if (t != "color3") { + return res; + } + res.node = node; + } + return res; +} + +bool NodeItem::is_numeric() const +{ + std::string t = type(); + return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4"); +} + +std::string NodeItem::type() const +{ + return value ? value->getTypeString() : node->getType(); +} + +NodeItem NodeItem::arithmetic(const std::string &mx_category, + std::function func) const +{ + if (!is_numeric()) { + return empty(); + } + + std::string t = value ? value->getTypeString() : node->getType(); + NodeItem res(graph_); + if (value) { + if (t == "float") { + float v = value->asA(); + res.value = MaterialX::Value::createValue(func(v)); + } + else if (t == "color3") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + } + else if (t == "color4") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + } + else if (t == "vector2") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); + } + else if (t == "vector3") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + } + else if (t == "vector4") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + } + else { + BLI_assert_unreachable(); + } + } + else { + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.set_input("in", *this); + } + return res; +} + +NodeItem NodeItem::arithmetic(const NodeItem &other, + const std::string &mx_category, + std::function func) const +{ + NodeItem res = empty(); + if (!is_numeric() || !other.is_numeric()) { + return res; + } + + std::string t1 = type(); + std::string t2 = other.type(); + + if (value && other.value) { + std::string t = t1; + auto val1 = value; + auto val2 = other.value; + if (t1 != t2) { + if (t1 == "float") { + val1 = float_to_type(val1->asA(), t2); + t = t2; + } + else if (t2 == "float") { + val2 = float_to_type(val2->asA(), t1); + } + else { + return res; + } + } + + if (t == "float") { + float v1 = val1->asA(); + float v2 = val2->asA(); + res.value = MaterialX::Value::createValue(func(v1, v2)); + } + else if (t == "color3") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + } + else if (t == "color4") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + } + else if (t == "vector2") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1])}); + } + else if (t == "vector3") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + } + else if (t == "vector4") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + } + else { + BLI_assert_unreachable(); + } + } + else { + std::string t = t1; + auto val1 = *this; + auto val2 = other; + if (t1 != t2) { + if (val1.value && t1 == "float") { + val1.value = float_to_type(val1.value->asA(), t2); + t = t2; + } + else if (val2.value && t2 == "float") { + val2.value = float_to_type(val2.value->asA(), t1); + } + else { + return res; + } + } + + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.set_input("in1", val1); + res.set_input("in2", val2); + } + return res; +} + +MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const +{ + if (t == "float") { + return MaterialX::Value::createValue(v); + } + if (t == "color3") { + return MaterialX::Value::createValue({v, v, v}); + } + if (t == "color4") { + return MaterialX::Value::createValue({v, v, v, 1.0f}); + } + if (t == "vector2") { + return MaterialX::Value::createValue({v, v}); + } + if (t == "vector3") { + return MaterialX::Value::createValue({v, v, v}); + } + if (t == "vector4") { + return MaterialX::Value::createValue({v, v, v, 1.0f}); + } + + BLI_assert_unreachable(); + return nullptr; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h new file mode 100644 index 000000000000..04c0438a1ec9 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -0,0 +1,87 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +namespace blender::nodes::materialx { + +class NodeItem { + public: + MaterialX::ValuePtr value; + MaterialX::NodePtr node; + + private: + MaterialX::GraphElement *graph_; + + public: + NodeItem(MaterialX::GraphElement *graph); + ~NodeItem() = default; + + NodeItem empty() const; + template NodeItem val(const T &data) const; + + template + void set_input(const std::string &name, const T &value, const std::string &mx_type); + void set_input(const std::string &name, const NodeItem &item); + void set_input(const std::string &name, const MaterialX::ValuePtr value); + void set_input(const std::string &name, const MaterialX::NodePtr node); + + operator bool() const; + NodeItem operator+(const NodeItem &other) const; + NodeItem operator-(const NodeItem &other) const; + NodeItem operator*(const NodeItem &other) const; + NodeItem operator/(const NodeItem &other) const; + NodeItem operator%(const NodeItem &other) const; + NodeItem operator^(const NodeItem &other) const; + bool operator==(const NodeItem &other) const; + + NodeItem abs() const; + NodeItem floor() const; + NodeItem ceil() const; + NodeItem min(const NodeItem &other) const; + NodeItem max(const NodeItem &other) const; + NodeItem dot(const NodeItem &other) const; + NodeItem if_else(char condition, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const; + NodeItem blend(const NodeItem &a, const NodeItem &b) const; + NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const; + NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const; + NodeItem sin() const; + NodeItem cos() const; + NodeItem tan() const; + NodeItem asin() const; + NodeItem acos() const; + NodeItem atan() const; + NodeItem log() const; + + NodeItem to_color3() const; + bool is_numeric() const; + std::string type() const; + + private: + NodeItem arithmetic(const std::string &mx_category, std::function func) const; + NodeItem arithmetic(const NodeItem &other, + const std::string &mx_category, + std::function func) const; + MaterialX::ValuePtr float_to_type(float v, std::string t) const; +}; + +template NodeItem NodeItem::val(const T &data) const +{ + NodeItem res(graph_); + res.value = MaterialX::Value::createValue(data); + return res; +} + +template +void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) +{ + node->setInputValue(name, value, mx_type); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 179897324427..e23d9415841b 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -8,460 +8,6 @@ namespace blender::nodes::materialx { -NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} - -NodeItem NodeItem::empty() const -{ - return NodeItem(graph_); -} - -void NodeItem::set_input(const std::string &name, const NodeItem &item) -{ - if (item.value) { - set_input(name, item.value); - } - else if (item.node) { - set_input(name, item.node); - } -} - -void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) -{ - std::string mx_type = value->getTypeString(); - if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else { - BLI_assert_unreachable(); - } -} - -void NodeItem::set_input(const std::string &name, const MaterialX::NodePtr node) -{ - this->node->setConnectedNode(name, node); -} - -NodeItem::operator bool() const -{ - return value || node; -} - -NodeItem NodeItem::operator+(const NodeItem &other) const -{ - return arithmetic(other, "add", [](float a, float b) { return a + b; }); -} - -NodeItem NodeItem::operator-(const NodeItem &other) const -{ - return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); -} - -NodeItem NodeItem::operator*(const NodeItem &other) const -{ - return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); -} - -NodeItem NodeItem::operator/(const NodeItem &other) const -{ - return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); -} - -NodeItem NodeItem::operator%(const NodeItem &other) const -{ - return arithmetic( - other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmodf(a, b); }); -} - -NodeItem NodeItem::operator^(const NodeItem &other) const -{ - return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); }); -} - -bool NodeItem::operator==(const NodeItem &other) const -{ - if (node && node == other.node) { - return true; - } - /* TODO: implement */ - return false; -} - -NodeItem NodeItem::abs() const -{ - return arithmetic("absval", [](float a) { return std::fabsf(a); }); -} - -NodeItem NodeItem::floor() const -{ - return arithmetic("floor", [](float a) { return std::floorf(a); }); -} - -NodeItem NodeItem::ceil() const -{ - return arithmetic("ceil", [](float a) { return std::ceilf(a); }); -} - -NodeItem NodeItem::min(const NodeItem &other) const -{ - return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); -} - -NodeItem NodeItem::max(const NodeItem &other) const -{ - return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); -} - -NodeItem NodeItem::dot(const NodeItem &other) const -{ - NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); - if (d.value) { - std::string t = d.type(); - float f = 0.0f; - if (t == "float") { - f = value->asA(); - } - else if (t == "color3") { - auto v = value->asA(); - f = v[0] + v[1] + v[2]; - } - else if (t == "color4") { - auto v = value->asA(); - f = v[0] + v[1] + v[2] + v[3]; - } - else if (t == "vector2") { - auto v = value->asA(); - f = v[0] + v[1]; - } - else if (t == "vector3") { - auto v = value->asA(); - f = v[0] + v[1] + v[2]; - } - else if (t == "vector4") { - auto v = value->asA(); - f = v[0] + v[1] + v[2] + v[3]; - } - d.value = MaterialX::Value::createValue(f); - } - return d; -} - -NodeItem NodeItem::if_else(char condition, - const NodeItem &other, - const NodeItem &if_val, - const NodeItem &else_val) const -{ - //def if_else(self, cond: str, other, if_value, else_value): - // if cond == '>': - // res = self._arithmetic_helper(other, 'ifgreater', lambda a, b: float(a > b)) - // elif cond == '>=': - // res = self._arithmetic_helper(other, 'ifgreatereq', lambda a, b: float(a >= b)) - // elif cond == '==': - // res = self._arithmetic_helper(other, 'ifequal', lambda a, b: float(a == b)) - // elif cond == '<': - // return self.node_item(other).if_else('>', self, else_value, if_value) - // elif cond == '<=': - // return self.node_item(other).if_else('>=', self, else_value, if_value) - // elif cond == '!=': - // return self.if_else('==', other, else_value, if_value) - // else: - // raise ValueError("Incorrect condition:", cond) - - // if isinstance(res.data, float): - // return if_value if res.data == 1.0 else else_value - // elif isinstance(res.data, tuple): - // return if_value if res.data[0] == 1.0 else else_value - // else: - // res.set_input('value1', if_value) - // res.set_input('value2', else_value) - // return res - return empty(); -} - -NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const -{ - return (val(1.0f) - *this) * a + *this * b; -} - -NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const -{ - return min(max_val).max(min_val); -} - -NodeItem NodeItem::clamp(float min_val, float max_val) const -{ - return clamp(val(min_val), val(max_val)); -} - -NodeItem NodeItem::sin() const -{ - return arithmetic("sin", [](float a) { return std::sinf(a); }); -} - -NodeItem NodeItem::cos() const -{ - return arithmetic("cos", [](float a) { return std::cosf(a); }); -} - -NodeItem NodeItem::tan() const -{ - return arithmetic("tan", [](float a) { return std::tanf(a); }); -} - -NodeItem NodeItem::asin() const -{ - return arithmetic("asin", [](float a) { return std::asinf(a); }); -} - -NodeItem NodeItem::acos() const -{ - return arithmetic("acos", [](float a) { return std::acosf(a); }); -} - -NodeItem NodeItem::atan() const -{ - return arithmetic("atan", [](float a) { return std::atanf(a); }); -} - -NodeItem NodeItem::log() const -{ - return arithmetic("ln", [](float a) { return std::logf(a); }); -} - -NodeItem NodeItem::to_color3() const -{ - std::string t = type(); - NodeItem res = empty(); - if (value) { - MaterialX::Color3 c; - if (t == "float") { - float v = value->asA(); - c = {v, v, v}; - } - else if (t == "color3") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (t == "color4") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (t == "vector3") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (t == "vector4") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else { - return res; - } - res.value = MaterialX::Value::createValue(c); - } - else if (node) { - if (t != "color3") { - return res; - } - res.node = node; - } - return res; -} - -bool NodeItem::is_numeric() const -{ - std::string t = type(); - return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4"); -} - -std::string NodeItem::type() const -{ - return value ? value->getTypeString() : node->getType(); -} - -NodeItem NodeItem::arithmetic(const std::string &mx_category, - std::function func) const -{ - if (!is_numeric()) { - return empty(); - } - - std::string t = value ? value->getTypeString() : node->getType(); - NodeItem res(graph_); - if (value) { - if (t == "float") { - float v = value->asA(); - res.value = MaterialX::Value::createValue(func(v)); - } - else if (t == "color3") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2])}); - } - else if (t == "color4") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); - } - else if (t == "vector2") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); - } - else if (t == "vector3") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2])}); - } - else if (t == "vector4") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); - } - else { - BLI_assert_unreachable(); - } - } - else { - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); - res.set_input("in", *this); - } - return res; -} - -NodeItem NodeItem::arithmetic(const NodeItem &other, - const std::string &mx_category, - std::function func) const -{ - NodeItem res = empty(); - if (!is_numeric() || !other.is_numeric()) { - return res; - } - - std::string t1 = type(); - std::string t2 = other.type(); - - if (value && other.value) { - std::string t = t1; - auto val1 = value; - auto val2 = other.value; - if (t1 != t2) { - if (t1 == "float") { - val1 = float_to_type(val1->asA(), t2); - t = t2; - } - else if (t2 == "float") { - val2 = float_to_type(val2->asA(), t1); - } - else { - return res; - } - } - - if (t == "float") { - float v1 = val1->asA(); - float v2 = val2->asA(); - res.value = MaterialX::Value::createValue(func(v1, v2)); - } - else if (t == "color3") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); - } - else if (t == "color4") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); - } - else if (t == "vector2") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1])}); - } - else if (t == "vector3") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); - } - else if (t == "vector4") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); - } - else { - BLI_assert_unreachable(); - } - } - else { - std::string t = t1; - auto val1 = *this; - auto val2 = other; - if (t1 != t2) { - if (val1.value && t1 == "float") { - val1.value = float_to_type(val1.value->asA(), t2); - t = t2; - } - else if (val2.value && t2 == "float") { - val2.value = float_to_type(val2.value->asA(), t1); - } - else { - return res; - } - } - - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); - res.set_input("in1", val1); - res.set_input("in2", val2); - } - return res; -} - -MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const -{ - if (t == "float") { - return MaterialX::Value::createValue(v); - } - if (t == "color3") { - return MaterialX::Value::createValue({v, v, v}); - } - if (t == "color4") { - return MaterialX::Value::createValue({v, v, v, 1.0f}); - } - if (t == "vector2") { - return MaterialX::Value::createValue({v, v}); - } - if (t == "vector3") { - return MaterialX::Value::createValue({v, v, v}); - } - if (t == "vector4") { - return MaterialX::Value::createValue({v, v, v, 1.0f}); - } - - BLI_assert_unreachable(); - return nullptr; -} - NodeParser::NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 033184c0d139..f9a100a219ed 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -4,7 +4,7 @@ #pragma once -#include +#include "node_item.h" #include "DEG_depsgraph.h" #include "DNA_material_types.h" @@ -12,82 +12,6 @@ namespace blender::nodes::materialx { -class NodeItem { - public: - MaterialX::ValuePtr value; - MaterialX::NodePtr node; - - private: - MaterialX::GraphElement *graph_; - - public: - NodeItem(MaterialX::GraphElement *graph); - ~NodeItem() = default; - - NodeItem empty() const; - template NodeItem val(const T &data) const; - - template - void set_input(const std::string &name, const T &value, const std::string &mx_type); - void set_input(const std::string &name, const NodeItem &item); - void set_input(const std::string &name, const MaterialX::ValuePtr value); - void set_input(const std::string &name, const MaterialX::NodePtr node); - - operator bool() const; - NodeItem operator+(const NodeItem &other) const; - NodeItem operator-(const NodeItem &other) const; - NodeItem operator*(const NodeItem &other) const; - NodeItem operator/(const NodeItem &other) const; - NodeItem operator%(const NodeItem &other) const; - NodeItem operator^(const NodeItem &other) const; - bool operator==(const NodeItem &other) const; - - NodeItem abs() const; - NodeItem floor() const; - NodeItem ceil() const; - NodeItem min(const NodeItem &other) const; - NodeItem max(const NodeItem &other) const; - NodeItem dot(const NodeItem &other) const; - NodeItem if_else(char condition, - const NodeItem &other, - const NodeItem &if_val, - const NodeItem &else_val) const; - NodeItem blend(const NodeItem &a, const NodeItem &b) const; - NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const; - NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const; - NodeItem sin() const; - NodeItem cos() const; - NodeItem tan() const; - NodeItem asin() const; - NodeItem acos() const; - NodeItem atan() const; - NodeItem log() const; - - NodeItem to_color3() const; - bool is_numeric() const; - std::string type() const; - - private: - NodeItem arithmetic(const std::string &mx_category, std::function func) const; - NodeItem arithmetic(const NodeItem &other, - const std::string &mx_category, - std::function func) const; - MaterialX::ValuePtr float_to_type(float v, std::string t) const; -}; - -template NodeItem NodeItem::val(const T &data) const -{ - NodeItem res(graph_); - res.value = MaterialX::Value::createValue(data); - return res; -} - -template -void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) -{ - node->setInputValue(name, value, mx_type); -} - class NodeParser { public: MaterialX::GraphElement *graph; -- 2.30.2 From 612b6a370edc250ac10b3b5b0ebf94da0f2cdf57 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Wed, 30 Aug 2023 13:51:40 +0300 Subject: [PATCH 3/9] Implemented Nodeitem::if_else() and operator "==" --- .../nodes/shader/materialx/nodes/node_item.cc | 63 +++++++++++-------- .../nodes/shader/materialx/nodes/node_item.h | 2 +- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index e1473399a78d..7b26daf53a13 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -101,7 +101,10 @@ bool NodeItem::operator==(const NodeItem &other) const if (node && node == other.node) { return true; } - /* TODO: implement */ + if (value && other.value) { + NodeItem cmp = if_else("==", other, val(1.0f), val(0.0f)); + return cmp.value->asA() == 1.0f; + } return false; } @@ -164,36 +167,44 @@ NodeItem NodeItem::dot(const NodeItem &other) const return d; } -NodeItem NodeItem::if_else(char condition, +NodeItem NodeItem::if_else(const std::string &condition, const NodeItem &other, const NodeItem &if_val, const NodeItem &else_val) const { - //def if_else(self, cond: str, other, if_value, else_value): - // if cond == '>': - // res = self._arithmetic_helper(other, 'ifgreater', lambda a, b: float(a > b)) - // elif cond == '>=': - // res = self._arithmetic_helper(other, 'ifgreatereq', lambda a, b: float(a >= b)) - // elif cond == '==': - // res = self._arithmetic_helper(other, 'ifequal', lambda a, b: float(a == b)) - // elif cond == '<': - // return self.node_item(other).if_else('>', self, else_value, if_value) - // elif cond == '<=': - // return self.node_item(other).if_else('>=', self, else_value, if_value) - // elif cond == '!=': - // return self.if_else('==', other, else_value, if_value) - // else: - // raise ValueError("Incorrect condition:", cond) + if (condition == "<") { + return other.if_else(">", *this, else_val, if_val); + } + if (condition == "<=") { + return other.if_else(">=", *this, else_val, if_val); + } + if (condition == "!=") { + return if_else("==", other, else_val, if_val); + } - // if isinstance(res.data, float): - // return if_value if res.data == 1.0 else else_value - // elif isinstance(res.data, tuple): - // return if_value if res.data[0] == 1.0 else else_value - // else: - // res.set_input('value1', if_value) - // res.set_input('value2', else_value) - // return res - return empty(); + NodeItem res = empty(); + if (condition == ">") { + res = arithmetic(other, "ifgreater", [](float a, float b) { return float(a > b); }); + } + else if (condition == ">=") { + res = arithmetic(other, "ifgreatereq", [](float a, float b) { return float(a >= b); }); + } + else if (condition == "==") { + res = arithmetic(other, "ifequal", [](float a, float b) { return float(a == b); }); + } + else { + BLI_assert_unreachable(); + } + + if (res.value) { + /* Getting sum of elements via dot product with 1.0f and comparing to 0.0f */ + res = res.dot(val(1.0f)).value->asA() == 0.0f ? else_val : if_val; + } + else if (res.node) { + res.set_input("value1", if_val); + res.set_input("value2", else_val); + } + return res; } NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 04c0438a1ec9..584a21f8aab1 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -44,7 +44,7 @@ class NodeItem { NodeItem min(const NodeItem &other) const; NodeItem max(const NodeItem &other) const; NodeItem dot(const NodeItem &other) const; - NodeItem if_else(char condition, + NodeItem if_else(const std::string &condition, const NodeItem &other, const NodeItem &if_val, const NodeItem &else_val) const; -- 2.30.2 From 9a4ada236d028228cfeb3013bf0bc469aaaf09a0 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Wed, 30 Aug 2023 14:18:57 +0300 Subject: [PATCH 4/9] Simplified bsdf_principled --- .../shader/materialx/nodes/bsdf_principled.cc | 41 ++++++------------- .../nodes/shader/materialx/nodes/node_item.cc | 5 +++ .../nodes/shader/materialx/nodes/node_item.h | 1 + .../shader/materialx/nodes/node_parser.cc | 2 +- .../shader/materialx/nodes/node_parser.h | 8 +++- 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 10c19cb4f7d3..3da7211f7ddf 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -8,22 +8,7 @@ namespace blender::nodes::materialx { NodeItem BSDFPrincipledNodeParser::compute() { - auto enabled = [](NodeItem &val) -> bool { - if (val.node) { - return true; - } - if (!val.value) { - return false; - } - if (val.value->isA()) { - return val.value->asA() != 0.0f; - } - if (val.value->isA()) { - auto c = val.value->asA(); - return c[0] != 0.0f || c[1] != 0.0f || c[2] != 0.0f; - } - return true; - }; + NodeItem zero = value(0.0f); /* Getting required inputs * Note: if some inputs are not needed they won't be taken */ @@ -32,7 +17,7 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem subsurface = get_input_value("Subsurface"); NodeItem subsurface_radius = empty(); NodeItem subsurface_color = empty(); - if (enabled(subsurface)) { + if (subsurface != zero) { subsurface_radius = get_input_value("Subsurface Radius"); subsurface_color = get_input_value("Subsurface Color"); } @@ -44,10 +29,10 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem anisotropic = empty(); NodeItem anisotropic_rotation = empty(); - if (enabled(metallic)) { + if (metallic != zero) { /* TODO: use Specular Tint input */ anisotropic = get_input_value("Anisotropic"); - if (enabled(anisotropic)) { + if (anisotropic != zero) { anisotropic_rotation = get_input_value("Anisotropic Rotation"); // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) } @@ -60,7 +45,7 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem clearcoat = get_input_value("Clearcoat"); NodeItem clearcoat_roughness = empty(); - if (enabled(clearcoat)) { + if (clearcoat != zero) { clearcoat_roughness = get_input_value("Clearcoat Roughness"); } @@ -68,7 +53,7 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem transmission = get_input_value("Transmission"); NodeItem transmission_roughness = empty(); - if (enabled(transmission)) { + if (transmission != zero) { transmission_roughness = get_input_value("Transmission Roughness"); } @@ -90,11 +75,11 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("normal", normal); res.set_input("tangent", tangent); - if (enabled(metallic)) { + if (metallic != zero) { res.set_input("metalness", metallic); } - if (enabled(specular)) { + if (specular != zero) { res.set_input("specular", specular); res.set_input("specular_color", base_color.to_color3()); res.set_input("specular_roughness", roughness); @@ -103,26 +88,26 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("specular_rotation", anisotropic_rotation); } - if (enabled(transmission)) { + if (transmission != zero) { res.set_input("transmission", transmission); res.set_input("transmission_color", base_color.to_color3()); res.set_input("transmission_extra_roughness", transmission_roughness); } - if (enabled(subsurface)) { + if (subsurface != zero) { res.set_input("subsurface", subsurface); res.set_input("subsurface_color", subsurface_color); res.set_input("subsurface_radius", subsurface_radius); res.set_input("subsurface_anisotropy", anisotropic); } - if (enabled(sheen)) { + if (sheen != zero) { res.set_input("sheen", sheen); res.set_input("sheen_color", base_color.to_color3()); res.set_input("sheen_roughness", roughness); } - if (enabled(clearcoat)) { + if (clearcoat != zero) { res.set_input("coat", clearcoat); res.set_input("coat_color", base_color.to_color3()); res.set_input("coat_roughness", clearcoat_roughness); @@ -132,7 +117,7 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("coat_normal", clearcoat_normal); } - if (enabled(emission)) { + if (emission != zero) { res.set_input("emission", emission_strength); res.set_input("emission_color", emission); } diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 7b26daf53a13..43c695a667cb 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -108,6 +108,11 @@ bool NodeItem::operator==(const NodeItem &other) const return false; } +bool NodeItem::operator!=(const NodeItem &other) const +{ + return !(*this == other); +} + NodeItem NodeItem::abs() const { return arithmetic("absval", [](float a) { return std::fabsf(a); }); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 584a21f8aab1..7734b4839968 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -37,6 +37,7 @@ class NodeItem { NodeItem operator%(const NodeItem &other) const; NodeItem operator^(const NodeItem &other) const; bool operator==(const NodeItem &other) const; + bool operator!=(const NodeItem &other) const; NodeItem abs() const; NodeItem floor() const; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index e23d9415841b..8751aceb1c00 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -111,7 +111,7 @@ NodeItem NodeParser::get_input_value(const std::string &name) return res; } -NodeItem NodeParser::empty() +NodeItem NodeParser::empty() const { return NodeItem(graph); } diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index f9a100a219ed..b7bcdade1c93 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -35,9 +35,15 @@ class NodeParser { NodeItem get_input_default(const std::string &name); NodeItem get_input_link(const std::string &name); NodeItem get_input_value(const std::string &name); - NodeItem empty(); + NodeItem empty() const; + template NodeItem value(const T &data) const; }; +template NodeItem NodeParser::value(const T &data) const +{ + return empty().val(data); +} + #define DECLARE_PARSER(T) \ class T : public NodeParser { \ public: \ -- 2.30.2 From b2cb85ad4830fce7689142f4305f8d9964e2ed84 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Wed, 30 Aug 2023 19:29:21 +0300 Subject: [PATCH 5/9] Implementing Math node. Added more arithmetic to NodeItem --- .../nodes/shader/materialx/nodes/math.cc | 159 +++++++++++++++++- .../nodes/shader/materialx/nodes/node_item.cc | 37 +++- .../nodes/shader/materialx/nodes/node_item.h | 9 +- .../shader/materialx/nodes/node_parser.cc | 52 ++++-- .../shader/materialx/nodes/node_parser.h | 8 + 5 files changed, 249 insertions(+), 16 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index ad5901d367c6..cfce90f27ba6 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -8,8 +8,163 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { - /* TODO: implement */ - return empty(); + auto op = node->custom1; + printf("%d\n", int(op)); + + NodeItem res = empty(); + + /* Single operand operations */ + NodeItem x = get_input_value(0); + switch (op) { + case NODE_MATH_SINE: + res = x.sin(); + break; + case NODE_MATH_COSINE: + res = x.cos(); + break; + case NODE_MATH_TANGENT: + res = x.tan(); + break; + case NODE_MATH_ARCSINE: + res = x.asin(); + break; + case NODE_MATH_ARCCOSINE: + res = x.acos(); + break; + case NODE_MATH_ARCTANGENT: + res = x.atan(); + break; + case NODE_MATH_ROUND: + res = (x + value(0.5f)).floor(); + break; + case NODE_MATH_ABSOLUTE: + res = x.abs(); + break; + case NODE_MATH_FLOOR: + res = x.floor(); + break; + case NODE_MATH_CEIL: + res = x.ceil(); + break; + case NODE_MATH_FRACTION: + res = x % value(1.0f); + break; + case NODE_MATH_SQRT: + res = x.sqrt(); + break; + case NODE_MATH_INV_SQRT: + res = value(1.0f) / x.sqrt(); + break; + case NODE_MATH_SIGN: + res = x.sign(); + break; + case NODE_MATH_EXPONENT: + res = x.exp(); + break; + case NODE_MATH_RADIANS: + res = x * value(float(M_PI) / 180.0f); + break; + case NODE_MATH_DEGREES: + res = x * value(180.0f * float(M_1_PI)); + break; + case NODE_MATH_SINH: + res = x.sinh(); + break; + case NODE_MATH_COSH: + res = x.cosh(); + break; + case NODE_MATH_TANH: + res = x.tanh(); + break; + + default: { + /* 2-operand operations */ + NodeItem y = get_input_value(1); + switch (op) { + case NODE_MATH_ADD: + res = x + y; + break; + case NODE_MATH_SUBTRACT: + res = x - y; + break; + case NODE_MATH_MULTIPLY: + res = x * y; + break; + case NODE_MATH_DIVIDE: + res = x / y; + break; + case NODE_MATH_POWER: + res = x ^ y; + break; + case NODE_MATH_LOGARITHM: + res = x.ln() / y.ln(); + break; + case NODE_MATH_MINIMUM: + res = x.min(y); + break; + case NODE_MATH_MAXIMUM: + res = x.max(y); + break; + case NODE_MATH_LESS_THAN: + res = x.if_else("<", y, value(1.0f), value(0.0f)); + break; + case NODE_MATH_GREATER_THAN: + res = x.if_else(">", y, value(1.0f), value(0.0f)); + break; + case NODE_MATH_MODULO: + res = x % y; + break; + case NODE_MATH_ARCTAN2: + res = x.atan2(y); + break; + case NODE_MATH_TRUNC: + //res = x.atan2(y); + break; + case NODE_MATH_SNAP: + //res = x.atan2(y); + break; + case NODE_MATH_PINGPONG: + //res = x.atan2(y); + break; + case NODE_MATH_FLOORED_MODULO: + //res = x.atan2(y); + break; + + default: { + /* 3-operand operations */ + NodeItem z = get_input_value(2); + switch (op) { + case NODE_MATH_WRAP: + //res = x * y + z; + break; + case NODE_MATH_COMPARE: + //res = x * y + z; + break; + case NODE_MATH_MULTIPLY_ADD: + res = x * y + z; + break; + case NODE_MATH_SMOOTH_MIN: + //res = x * y + z; + break; + case NODE_MATH_SMOOTH_MAX: + //res = x * y + z; + break; + + default: + /* TODO: log unsupported operation*/ + } + } + } + + } + } + + bool clamp_output = node->custom2 != 0; + if (clamp_output && res) { + res = res.clamp(); + } + + return res; } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 43c695a667cb..aeabb33bc4e9 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -257,11 +257,46 @@ NodeItem NodeItem::atan() const return arithmetic("atan", [](float a) { return std::atanf(a); }); } -NodeItem NodeItem::log() const +NodeItem NodeItem::atan2(const NodeItem &other) const +{ + return arithmetic(other, "atan2", [](float a, float b) { return std::atan2f(a, b); }); +} + +NodeItem NodeItem::sinh() const +{ + return exp() - (val(0.0f) - *this).exp()) / val(2.0f); +} + +NodeItem NodeItem::cosh() const +{ + return exp() - (val(0.0f) - *this).exp()) / val(2.0f); +} + +NodeItem NodeItem::tanh() const +{ + return sinh() / cosh(); +} + +NodeItem NodeItem::ln() const { return arithmetic("ln", [](float a) { return std::logf(a); }); } +NodeItem NodeItem::sqrt() const +{ + return arithmetic("sqrt", [](float a) { return std::sqrtf(a); }); +} + +NodeItem NodeItem::sign() const +{ + return arithmetic("sign", [](float a) { return a < 0.0f ? -1.0f : (a == 0.0f ? 0.0f : 1.0f); }); +} + +NodeItem NodeItem::exp() const +{ + return arithmetic("exp", [](float a) { return std::expf(a); }); +} + NodeItem NodeItem::to_color3() const { std::string t = type(); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 7734b4839968..915d178eaf5f 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -58,7 +58,14 @@ class NodeItem { NodeItem asin() const; NodeItem acos() const; NodeItem atan() const; - NodeItem log() const; + NodeItem atan2(const NodeItem &other) const; + NodeItem sinh() const; + NodeItem cosh() const; + NodeItem tanh() const; + NodeItem ln() const; + NodeItem sqrt() const; + NodeItem sign() const; + NodeItem exp() const; NodeItem to_color3() const; bool is_numeric() const; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 8751aceb1c00..61bda4d32628 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -30,9 +30,42 @@ NodeItem NodeParser::create_node(const std::string &mx_category, NodeItem NodeParser::get_input_default(const std::string &name) { - NodeItem res = empty(); + return get_input_default(node->input_by_identifier(name)); +} - const bNodeSocket &socket = node->input_by_identifier(name); +NodeItem NodeParser::get_input_default(int index) +{ + return get_input_default(node->input_socket(index)); +} + +NodeItem NodeParser::get_input_link(const std::string &name) +{ + return get_input_link(node->input_by_identifier(name)); +} + +NodeItem NodeParser::get_input_link(int index) +{ + return get_input_link(node->input_socket(index)); +} + +NodeItem NodeParser::get_input_value(const std::string &name) +{ + return get_input_value(node->input_by_identifier(name)); +} + +NodeItem NodeParser::get_input_value(int index) +{ + return get_input_value(node->input_socket(index)); +} + +NodeItem NodeParser::empty() const +{ + return NodeItem(graph); +} + +NodeItem NodeParser::get_input_default(const bNodeSocket &socket) +{ + NodeItem res = empty(); switch (socket.type) { case SOCK_FLOAT: { float v = socket.default_value_typed()->value; @@ -55,11 +88,11 @@ NodeItem NodeParser::get_input_default(const std::string &name) return res; } -NodeItem NodeParser::get_input_link(const std::string &name) +NodeItem NodeParser::get_input_link(const bNodeSocket &socket) { NodeItem res = empty(); - const bNodeLink *link = node->input_by_identifier(name).link; + const bNodeLink *link = socket.link; if (!(link && link->is_used())) { return res; } @@ -102,18 +135,13 @@ NodeItem NodeParser::get_input_link(const std::string &name) return res; } -NodeItem NodeParser::get_input_value(const std::string &name) +NodeItem NodeParser::get_input_value(const bNodeSocket &socket) { - NodeItem res = get_input_link(name); + NodeItem res = get_input_link(socket); if (!res) { - res = get_input_default(name); + res = get_input_default(socket); } return res; } -NodeItem NodeParser::empty() const -{ - return NodeItem(graph); -} - } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index b7bcdade1c93..4849e430bc35 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -33,10 +33,18 @@ class NodeParser { const std::string &mx_type, bool accessory = false); 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); + NodeItem get_input_value(int index); NodeItem empty() const; template NodeItem value(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); }; template NodeItem NodeParser::value(const T &data) const -- 2.30.2 From e1e66e4a1d37382ae408e3273c737dc226260863 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Wed, 30 Aug 2023 20:34:56 +0300 Subject: [PATCH 6/9] Improvements and fixes --- .../nodes/shader/materialx/nodes/math.cc | 25 ++++++++++--------- .../nodes/shader/materialx/nodes/node_item.cc | 20 +++++++++++++-- .../nodes/shader/materialx/nodes/node_item.h | 1 + 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index cfce90f27ba6..9fce9a7457d3 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -8,6 +8,8 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { + /* TODO: finish some math operations */ + auto op = node->custom1; printf("%d\n", int(op)); @@ -76,6 +78,9 @@ NodeItem MathNodeParser::compute() case NODE_MATH_TANH: res = x.tanh(); break; + case NODE_MATH_TRUNC: + res = x.sign() * x.abs().floor(); + break; default: { /* 2-operand operations */ @@ -117,17 +122,14 @@ NodeItem MathNodeParser::compute() case NODE_MATH_ARCTAN2: res = x.atan2(y); break; - case NODE_MATH_TRUNC: - //res = x.atan2(y); - break; case NODE_MATH_SNAP: - //res = x.atan2(y); + // res = ; break; case NODE_MATH_PINGPONG: - //res = x.atan2(y); + // res = ; break; case NODE_MATH_FLOORED_MODULO: - //res = x.atan2(y); + // res = ; break; default: { @@ -135,27 +137,26 @@ NodeItem MathNodeParser::compute() NodeItem z = get_input_value(2); switch (op) { case NODE_MATH_WRAP: - //res = x * y + z; + // res = ; break; case NODE_MATH_COMPARE: - //res = x * y + z; + res = z.if_else("<", (x - y).abs(), value(1.0f), value(0.0f)); break; case NODE_MATH_MULTIPLY_ADD: res = x * y + z; break; case NODE_MATH_SMOOTH_MIN: - //res = x * y + z; + // res = ; break; case NODE_MATH_SMOOTH_MAX: - //res = x * y + z; + // res = ; break; default: - /* TODO: log unsupported operation*/ + BLI_assert_unreachable(); } } } - } } diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index aeabb33bc4e9..f29f3a39b2db 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -75,6 +75,11 @@ NodeItem NodeItem::operator-(const NodeItem &other) const return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); } +NodeItem NodeItem::operator-() const +{ + return val(0.0f) - *this; +} + NodeItem NodeItem::operator*(const NodeItem &other) const { return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); @@ -177,6 +182,17 @@ NodeItem NodeItem::if_else(const std::string &condition, const NodeItem &if_val, const NodeItem &else_val) const { + /* TODO: if_else() doesn't work correctly. Here is description + * Node: + * Output the value of in1 if value1>value2, or the value of in2 if value1<=value2. + + + + + + + + */ if (condition == "<") { return other.if_else(">", *this, else_val, if_val); } @@ -264,12 +280,12 @@ NodeItem NodeItem::atan2(const NodeItem &other) const NodeItem NodeItem::sinh() const { - return exp() - (val(0.0f) - *this).exp()) / val(2.0f); + return (exp() - (-*this).exp()) / val(2.0f); } NodeItem NodeItem::cosh() const { - return exp() - (val(0.0f) - *this).exp()) / val(2.0f); + return (exp() - (-*this).exp()) / val(2.0f); } NodeItem NodeItem::tanh() const diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 915d178eaf5f..d268a19a14ca 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -32,6 +32,7 @@ class NodeItem { operator bool() const; NodeItem operator+(const NodeItem &other) const; NodeItem operator-(const NodeItem &other) const; + NodeItem operator-() const; NodeItem operator*(const NodeItem &other) const; NodeItem operator/(const NodeItem &other) const; NodeItem operator%(const NodeItem &other) const; -- 2.30.2 From 0517ab20a3b8533266e5ac0108f206d0644812fb Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 31 Aug 2023 02:14:55 +0300 Subject: [PATCH 7/9] Fixed if_else() and operator==(). Added adjust_types() --- .../nodes/shader/materialx/nodes/node_item.cc | 165 ++++++++++++------ .../nodes/shader/materialx/nodes/node_item.h | 4 +- 2 files changed, 117 insertions(+), 52 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index f29f3a39b2db..644b41e9605e 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -103,13 +103,44 @@ NodeItem NodeItem::operator^(const NodeItem &other) const bool NodeItem::operator==(const NodeItem &other) const { + if (!*this) { + return !other; + } + if (!other) { + return !*this; + } if (node && node == other.node) { return true; } - if (value && other.value) { - NodeItem cmp = if_else("==", other, val(1.0f), val(0.0f)); - return cmp.value->asA() == 1.0f; + if ((node && other.value) || (value && other.node)) { + return false; } + + std::string t; + auto val1 = value; + auto val2 = other.value; + if (!adjust_types(val1, val2, t)) { + return false; + } + if (t == "float") { + return val1->asA() == val2->asA(); + } + if (t == "color3") { + return val1->asA() == val2->asA(); + } + if (t == "color4") { + return val1->asA() == val2->asA(); + } + if (t == "vector2") { + return val1->asA() == val2->asA(); + } + if (t == "vector3") { + return val1->asA() == val2->asA(); + } + if (t == "vector4") { + return val1->asA() == val2->asA(); + } + return false; } @@ -182,17 +213,6 @@ NodeItem NodeItem::if_else(const std::string &condition, const NodeItem &if_val, const NodeItem &else_val) const { - /* TODO: if_else() doesn't work correctly. Here is description - * Node: - * Output the value of in1 if value1>value2, or the value of in2 if value1<=value2. - - - - - - - - */ if (condition == "<") { return other.if_else(">", *this, else_val, if_val); } @@ -204,27 +224,46 @@ NodeItem NodeItem::if_else(const std::string &condition, } NodeItem res = empty(); + if (type() != "float" || other.type() != "float") { + return res; + } + + auto val1 = if_val; + auto val2 = else_val; + std::string t; + if (!adjust_types(val1, val2, t)) { + return res; + } + + std::function func = nullptr; + std::string mx_category; if (condition == ">") { - res = arithmetic(other, "ifgreater", [](float a, float b) { return float(a > b); }); + mx_category = "ifgreater"; + func = [](float a, float b) { return a > b; }; } else if (condition == ">=") { - res = arithmetic(other, "ifgreatereq", [](float a, float b) { return float(a >= b); }); + mx_category = "ifgreatereq"; + func = [](float a, float b) { return a >= b; }; } else if (condition == "==") { - res = arithmetic(other, "ifequal", [](float a, float b) { return float(a == b); }); + mx_category = "ifequal"; + func = [](float a, float b) { return a == b; }; } else { BLI_assert_unreachable(); } - if (res.value) { - /* Getting sum of elements via dot product with 1.0f and comparing to 0.0f */ - res = res.dot(val(1.0f)).value->asA() == 0.0f ? else_val : if_val; + if (value && other.value) { + res = func(value->asA(), other.value->asA()) ? val1 : val2; } - else if (res.node) { - res.set_input("value1", if_val); - res.set_input("value2", else_val); + else { + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.set_input("value1", *this); + res.set_input("value2", other); + res.set_input("in1", val1); + res.set_input("in2", val2); } + return res; } @@ -422,24 +461,12 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, return res; } - std::string t1 = type(); - std::string t2 = other.type(); - + std::string t; if (value && other.value) { - std::string t = t1; auto val1 = value; auto val2 = other.value; - if (t1 != t2) { - if (t1 == "float") { - val1 = float_to_type(val1->asA(), t2); - t = t2; - } - else if (t2 == "float") { - val2 = float_to_type(val2->asA(), t1); - } - else { - return res; - } + if (!adjust_types(val1, val2, t)) { + return res; } if (t == "float") { @@ -482,20 +509,10 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, } } else { - std::string t = t1; auto val1 = *this; auto val2 = other; - if (t1 != t2) { - if (val1.value && t1 == "float") { - val1.value = float_to_type(val1.value->asA(), t2); - t = t2; - } - else if (val2.value && t2 == "float") { - val2.value = float_to_type(val2.value->asA(), t1); - } - else { - return res; - } + if (!adjust_types(val1, val2, t)) { + return res; } res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); @@ -505,7 +522,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, return res; } -MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const +MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) { if (t == "float") { return MaterialX::Value::createValue(v); @@ -530,4 +547,50 @@ MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const return nullptr; } +bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &t) +{ + std::string t1 = val1->getTypeString(); + std::string t2 = val2->getTypeString(); + if (t1 != t2) { + if (t1 == "float") { + val1 = float_to_type(val1->asA(), t2); + t = t2; + } + else if (t2 == "float") { + val2 = float_to_type(val2->asA(), t1); + t = t1; + } + else { + return false; + } + } + else { + t = t1; + } + return true; +} + +bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, std::string &t) +{ + std::string t1 = val1.type(); + std::string t2 = val2.type(); + if (t1 != t2) { + if (val1.value && t1 == "float") { + val1.value = float_to_type(val1.value->asA(), t2); + t = t2; + } + else if (val2.value && t2 == "float") { + val2.value = float_to_type(val2.value->asA(), t1); + t = t2; + } + else { + return false; + } + } + else { + t = t1; + } + return true; +} + } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index d268a19a14ca..c3b194ee67da 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -77,7 +77,9 @@ class NodeItem { NodeItem arithmetic(const NodeItem &other, const std::string &mx_category, std::function func) const; - MaterialX::ValuePtr float_to_type(float v, std::string t) const; + static MaterialX::ValuePtr float_to_type(float v, std::string t); + static bool adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &t); + static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &t); }; template NodeItem NodeItem::val(const T &data) const -- 2.30.2 From 408b336e6e6f50b1317de4a05b54fb347139d817 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 31 Aug 2023 11:32:29 +0300 Subject: [PATCH 8/9] rename dot->dotproduct --- source/blender/nodes/shader/materialx/nodes/node_item.cc | 2 +- source/blender/nodes/shader/materialx/nodes/node_item.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 644b41e9605e..4c31a52167ae 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -174,7 +174,7 @@ NodeItem NodeItem::max(const NodeItem &other) const return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); } -NodeItem NodeItem::dot(const NodeItem &other) const +NodeItem NodeItem::dotproduct(const NodeItem &other) const { NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); if (d.value) { diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index c3b194ee67da..1bf34eb2cde4 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -45,7 +45,7 @@ class NodeItem { NodeItem ceil() const; NodeItem min(const NodeItem &other) const; NodeItem max(const NodeItem &other) const; - NodeItem dot(const NodeItem &other) const; + NodeItem dotproduct(const NodeItem &other) const; NodeItem if_else(const std::string &condition, const NodeItem &other, const NodeItem &if_val, -- 2.30.2 From 620fbc6af893cb698aab156946dc1b9885849e8e Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 31 Aug 2023 12:12:33 +0300 Subject: [PATCH 9/9] Renamings + fix adjust_types() --- .../nodes/shader/materialx/nodes/node_item.cc | 103 +++++++++--------- .../nodes/shader/materialx/nodes/node_item.h | 7 +- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 4c31a52167ae..8a65fe155a2b 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -29,25 +29,28 @@ void NodeItem::set_input(const std::string &name, const NodeItem &item) void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) { std::string mx_type = value->getTypeString(); - if (value->isA()) { + if (mx_type == "float") { set_input(name, value->asA(), mx_type); } - else if (value->isA()) { + else if (mx_type == "integer") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "vector2") { set_input(name, value->asA(), mx_type); } - else if (value->isA()) { + else if (mx_type == "vector3") { set_input(name, value->asA(), mx_type); } - else if (value->isA()) { + else if (mx_type == "vector4") { set_input(name, value->asA(), mx_type); } - else if (value->isA()) { + else if (mx_type == "color3") { set_input(name, value->asA(), mx_type); } - else if (value->isA()) { + else if (mx_type == "color4") { set_input(name, value->asA(), mx_type); } - else if (value->isA()) { + else if (mx_type == "string") { set_input(name, value->asA(), mx_type); } else { @@ -116,28 +119,28 @@ bool NodeItem::operator==(const NodeItem &other) const return false; } - std::string t; + std::string mx_type; auto val1 = value; auto val2 = other.value; - if (!adjust_types(val1, val2, t)) { + if (!adjust_types(val1, val2, mx_type)) { return false; } - if (t == "float") { + if (mx_type == "float") { return val1->asA() == val2->asA(); } - if (t == "color3") { + if (mx_type == "color3") { return val1->asA() == val2->asA(); } - if (t == "color4") { + if (mx_type == "color4") { return val1->asA() == val2->asA(); } - if (t == "vector2") { + if (mx_type == "vector2") { return val1->asA() == val2->asA(); } - if (t == "vector3") { + if (mx_type == "vector3") { return val1->asA() == val2->asA(); } - if (t == "vector4") { + if (mx_type == "vector4") { return val1->asA() == val2->asA(); } @@ -178,28 +181,28 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const { NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); if (d.value) { - std::string t = d.type(); + std::string mx_type = d.type(); float f = 0.0f; - if (t == "float") { + if (mx_type == "float") { f = value->asA(); } - else if (t == "color3") { + else if (mx_type == "color3") { auto v = value->asA(); f = v[0] + v[1] + v[2]; } - else if (t == "color4") { + else if (mx_type == "color4") { auto v = value->asA(); f = v[0] + v[1] + v[2] + v[3]; } - else if (t == "vector2") { + else if (mx_type == "vector2") { auto v = value->asA(); f = v[0] + v[1]; } - else if (t == "vector3") { + else if (mx_type == "vector3") { auto v = value->asA(); f = v[0] + v[1] + v[2]; } - else if (t == "vector4") { + else if (mx_type == "vector4") { auto v = value->asA(); f = v[0] + v[1] + v[2] + v[3]; } @@ -230,8 +233,8 @@ NodeItem NodeItem::if_else(const std::string &condition, auto val1 = if_val; auto val2 = else_val; - std::string t; - if (!adjust_types(val1, val2, t)) { + std::string mx_type; + if (!adjust_types(val1, val2, mx_type)) { return res; } @@ -257,7 +260,7 @@ NodeItem NodeItem::if_else(const std::string &condition, res = func(value->asA(), other.value->asA()) ? val1 : val2; } else { - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); res.set_input("value1", *this); res.set_input("value2", other); res.set_input("in1", val1); @@ -461,44 +464,44 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, return res; } - std::string t; + std::string mx_type; if (value && other.value) { auto val1 = value; auto val2 = other.value; - if (!adjust_types(val1, val2, t)) { + if (!adjust_types(val1, val2, mx_type)) { return res; } - if (t == "float") { + if (mx_type == "float") { float v1 = val1->asA(); float v2 = val2->asA(); res.value = MaterialX::Value::createValue(func(v1, v2)); } - else if (t == "color3") { + else if (mx_type == "color3") { auto v1 = val1->asA(); auto v2 = val2->asA(); res.value = MaterialX::Value::createValue( {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); } - else if (t == "color4") { + else if (mx_type == "color4") { auto v1 = val1->asA(); auto v2 = val2->asA(); res.value = MaterialX::Value::createValue( {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); } - else if (t == "vector2") { + else if (mx_type == "vector2") { auto v1 = val1->asA(); auto v2 = val2->asA(); res.value = MaterialX::Value::createValue( {func(v1[0], v2[0]), func(v1[1], v2[1])}); } - else if (t == "vector3") { + else if (mx_type == "vector3") { auto v1 = val1->asA(); auto v2 = val2->asA(); res.value = MaterialX::Value::createValue( {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); } - else if (t == "vector4") { + else if (mx_type == "vector4") { auto v1 = val1->asA(); auto v2 = val2->asA(); res.value = MaterialX::Value::createValue( @@ -511,35 +514,35 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, else { auto val1 = *this; auto val2 = other; - if (!adjust_types(val1, val2, t)) { + if (!adjust_types(val1, val2, mx_type)) { return res; } - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); res.set_input("in1", val1); res.set_input("in2", val2); } return res; } -MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) +MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string mx_type) { - if (t == "float") { + if (mx_type == "float") { return MaterialX::Value::createValue(v); } - if (t == "color3") { + if (mx_type == "color3") { return MaterialX::Value::createValue({v, v, v}); } - if (t == "color4") { + if (mx_type == "color4") { return MaterialX::Value::createValue({v, v, v, 1.0f}); } - if (t == "vector2") { + if (mx_type == "vector2") { return MaterialX::Value::createValue({v, v}); } - if (t == "vector3") { + if (mx_type == "vector3") { return MaterialX::Value::createValue({v, v, v}); } - if (t == "vector4") { + if (mx_type == "vector4") { return MaterialX::Value::createValue({v, v, v, 1.0f}); } @@ -547,48 +550,48 @@ MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) return nullptr; } -bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &t) +bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &mx_type) { std::string t1 = val1->getTypeString(); std::string t2 = val2->getTypeString(); if (t1 != t2) { if (t1 == "float") { val1 = float_to_type(val1->asA(), t2); - t = t2; + mx_type = t2; } else if (t2 == "float") { val2 = float_to_type(val2->asA(), t1); - t = t1; + mx_type = t1; } else { return false; } } else { - t = t1; + mx_type = t1; } return true; } -bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, std::string &t) +bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type) { std::string t1 = val1.type(); std::string t2 = val2.type(); if (t1 != t2) { if (val1.value && t1 == "float") { val1.value = float_to_type(val1.value->asA(), t2); - t = t2; + mx_type = t2; } else if (val2.value && t2 == "float") { val2.value = float_to_type(val2.value->asA(), t1); - t = t2; + mx_type = t1; } else { return false; } } else { - t = t1; + mx_type = t1; } return true; } diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 1bf34eb2cde4..26d3f58b02f9 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -77,9 +77,10 @@ class NodeItem { NodeItem arithmetic(const NodeItem &other, const std::string &mx_category, std::function func) const; - static MaterialX::ValuePtr float_to_type(float v, std::string t); - static bool adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &t); - static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &t); + static MaterialX::ValuePtr float_to_type(float v, std::string mx_type); + /* Functions for adjusting values to make equal types */ + static bool adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &mx_type); + static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type); }; template NodeItem NodeItem::val(const T &data) const -- 2.30.2