forked from blender/blender
Implement export of Math node. Continue other arithmetic support for NodeItem #6
@ -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()
|
||||
|
466
source/blender/nodes/shader/materialx/nodes/node_item.cc
Normal file
466
source/blender/nodes/shader/materialx/nodes/node_item.cc
Normal file
@ -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<float>()) {
|
||||
set_input(name, value->asA<float>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Vector2>()) {
|
||||
set_input(name, value->asA<MaterialX::Vector2>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Vector3>()) {
|
||||
set_input(name, value->asA<MaterialX::Vector3>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Vector4>()) {
|
||||
set_input(name, value->asA<MaterialX::Vector4>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Color3>()) {
|
||||
set_input(name, value->asA<MaterialX::Color3>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Color4>()) {
|
||||
set_input(name, value->asA<MaterialX::Color4>(), mx_type);
|
||||
}
|
||||
else if (value->isA<std::string>()) {
|
||||
set_input(name, value->asA<std::string>(), 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<float>();
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
f = v[0] + v[1] + v[2];
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v = value->asA<MaterialX::Color4>();
|
||||
f = v[0] + v[1] + v[2] + v[3];
|
||||
}
|
||||
else if (t == "vector2") {
|
||||
auto v = value->asA<MaterialX::Vector2>();
|
||||
f = v[0] + v[1];
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
f = v[0] + v[1] + v[2];
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v = value->asA<MaterialX::Vector4>();
|
||||
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<float>();
|
||||
c = {v, v, v};
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v = value->asA<MaterialX::Color4>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v = value->asA<MaterialX::Vector4>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color3>(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<float(float)> 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<float>();
|
||||
res.value = MaterialX::Value::createValue<float>(func(v));
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
||||
{func(v[0]), func(v[1]), func(v[2])});
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v = value->asA<MaterialX::Color4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
|
||||
{func(v[0]), func(v[1]), func(v[2]), func(v[3])});
|
||||
}
|
||||
else if (t == "vector2") {
|
||||
auto v = value->asA<MaterialX::Vector2>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
||||
{func(v[0]), func(v[1]), func(v[2])});
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v = value->asA<MaterialX::Vector4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
||||
{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<float(float, float)> 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<float>(), t2);
|
||||
t = t2;
|
||||
}
|
||||
else if (t2 == "float") {
|
||||
val2 = float_to_type(val2->asA<float>(), t1);
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (t == "float") {
|
||||
float v1 = val1->asA<float>();
|
||||
float v2 = val2->asA<float>();
|
||||
res.value = MaterialX::Value::createValue<float>(func(v1, v2));
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v1 = val1->asA<MaterialX::Color3>();
|
||||
auto v2 = val2->asA<MaterialX::Color3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
||||
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v1 = val1->asA<MaterialX::Color4>();
|
||||
auto v2 = val2->asA<MaterialX::Color4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
|
||||
{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<MaterialX::Vector2>();
|
||||
auto v2 = val2->asA<MaterialX::Vector2>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
|
||||
{func(v1[0], v2[0]), func(v1[1], v2[1])});
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v1 = val1->asA<MaterialX::Vector3>();
|
||||
auto v2 = val2->asA<MaterialX::Vector3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
||||
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v1 = val1->asA<MaterialX::Vector4>();
|
||||
auto v2 = val2->asA<MaterialX::Vector4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
||||
{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<float>(), t2);
|
||||
t = t2;
|
||||
}
|
||||
else if (val2.value && t2 == "float") {
|
||||
val2.value = float_to_type(val2.value->asA<float>(), 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<float>(v);
|
||||
}
|
||||
if (t == "color3") {
|
||||
return MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
|
||||
}
|
||||
if (t == "color4") {
|
||||
return MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
|
||||
}
|
||||
if (t == "vector2") {
|
||||
return MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
|
||||
}
|
||||
if (t == "vector3") {
|
||||
return MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
|
||||
}
|
||||
if (t == "vector4") {
|
||||
return MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
87
source/blender/nodes/shader/materialx/nodes/node_item.h
Normal file
87
source/blender/nodes/shader/materialx/nodes/node_item.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <MaterialXCore/Node.h>
|
||||
|
||||
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<class T> NodeItem val(const T &data) const;
|
||||
|
||||
template<class T>
|
||||
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<float(float)> func) const;
|
||||
NodeItem arithmetic(const NodeItem &other,
|
||||
const std::string &mx_category,
|
||||
std::function<float(float, float)> func) const;
|
||||
MaterialX::ValuePtr float_to_type(float v, std::string t) const;
|
||||
};
|
||||
|
||||
template<class T> NodeItem NodeItem::val(const T &data) const
|
||||
{
|
||||
NodeItem res(graph_);
|
||||
res.value = MaterialX::Value::createValue<T>(data);
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
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
|
@ -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<float>()) {
|
||||
set_input(name, value->asA<float>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Vector2>()) {
|
||||
set_input(name, value->asA<MaterialX::Vector2>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Vector3>()) {
|
||||
set_input(name, value->asA<MaterialX::Vector3>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Vector4>()) {
|
||||
set_input(name, value->asA<MaterialX::Vector4>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Color3>()) {
|
||||
set_input(name, value->asA<MaterialX::Color3>(), mx_type);
|
||||
}
|
||||
else if (value->isA<MaterialX::Color4>()) {
|
||||
set_input(name, value->asA<MaterialX::Color4>(), mx_type);
|
||||
}
|
||||
else if (value->isA<std::string>()) {
|
||||
set_input(name, value->asA<std::string>(), 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<float>();
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
f = v[0] + v[1] + v[2];
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v = value->asA<MaterialX::Color4>();
|
||||
f = v[0] + v[1] + v[2] + v[3];
|
||||
}
|
||||
else if (t == "vector2") {
|
||||
auto v = value->asA<MaterialX::Vector2>();
|
||||
f = v[0] + v[1];
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
f = v[0] + v[1] + v[2];
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v = value->asA<MaterialX::Vector4>();
|
||||
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<float>();
|
||||
c = {v, v, v};
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v = value->asA<MaterialX::Color4>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v = value->asA<MaterialX::Vector4>();
|
||||
c = {v[0], v[1], v[2]};
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color3>(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<float(float)> 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<float>();
|
||||
res.value = MaterialX::Value::createValue<float>(func(v));
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
||||
{func(v[0]), func(v[1]), func(v[2])});
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v = value->asA<MaterialX::Color4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
|
||||
{func(v[0]), func(v[1]), func(v[2]), func(v[3])});
|
||||
}
|
||||
else if (t == "vector2") {
|
||||
auto v = value->asA<MaterialX::Vector2>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
||||
{func(v[0]), func(v[1]), func(v[2])});
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v = value->asA<MaterialX::Vector4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
||||
{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<float(float, float)> 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<float>(), t2);
|
||||
t = t2;
|
||||
}
|
||||
else if (t2 == "float") {
|
||||
val2 = float_to_type(val2->asA<float>(), t1);
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (t == "float") {
|
||||
float v1 = val1->asA<float>();
|
||||
float v2 = val2->asA<float>();
|
||||
res.value = MaterialX::Value::createValue<float>(func(v1, v2));
|
||||
}
|
||||
else if (t == "color3") {
|
||||
auto v1 = val1->asA<MaterialX::Color3>();
|
||||
auto v2 = val2->asA<MaterialX::Color3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
||||
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
|
||||
}
|
||||
else if (t == "color4") {
|
||||
auto v1 = val1->asA<MaterialX::Color4>();
|
||||
auto v2 = val2->asA<MaterialX::Color4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
|
||||
{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<MaterialX::Vector2>();
|
||||
auto v2 = val2->asA<MaterialX::Vector2>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
|
||||
{func(v1[0], v2[0]), func(v1[1], v2[1])});
|
||||
}
|
||||
else if (t == "vector3") {
|
||||
auto v1 = val1->asA<MaterialX::Vector3>();
|
||||
auto v2 = val2->asA<MaterialX::Vector3>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
||||
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
|
||||
}
|
||||
else if (t == "vector4") {
|
||||
auto v1 = val1->asA<MaterialX::Vector4>();
|
||||
auto v2 = val2->asA<MaterialX::Vector4>();
|
||||
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
||||
{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<float>(), t2);
|
||||
t = t2;
|
||||
}
|
||||
else if (val2.value && t2 == "float") {
|
||||
val2.value = float_to_type(val2.value->asA<float>(), 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<float>(v);
|
||||
}
|
||||
if (t == "color3") {
|
||||
return MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
|
||||
}
|
||||
if (t == "color4") {
|
||||
return MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
|
||||
}
|
||||
if (t == "vector2") {
|
||||
return MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
|
||||
}
|
||||
if (t == "vector3") {
|
||||
return MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
|
||||
}
|
||||
if (t == "vector4") {
|
||||
return MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NodeParser::NodeParser(MaterialX::GraphElement *graph,
|
||||
const Depsgraph *depsgraph,
|
||||
const Material *material,
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <MaterialXCore/Document.h>
|
||||
#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<class T> NodeItem val(const T &data) const;
|
||||
|
||||
template<class T>
|
||||
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<float(float)> func) const;
|
||||
NodeItem arithmetic(const NodeItem &other,
|
||||
const std::string &mx_category,
|
||||
std::function<float(float, float)> func) const;
|
||||
MaterialX::ValuePtr float_to_type(float v, std::string t) const;
|
||||
};
|
||||
|
||||
template<class T> NodeItem NodeItem::val(const T &data) const
|
||||
{
|
||||
NodeItem res(graph_);
|
||||
res.value = MaterialX::Value::createValue<T>(data);
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user