Arithmetic support for NodeItem and node implementation with arithmetic #4

Merged
Bogdan Nagirniak merged 3 commits from BogdanNagirniak/blender:BLEN-512 into matx-export-material 2023-08-29 09:26:20 +02:00
5 changed files with 172 additions and 83 deletions
Showing only changes of commit 9b53dd3fc0 - Show all commits

View File

@ -10,7 +10,7 @@ NodeItem InvertNodeParser::compute()
{ {
NodeItem fac = get_input_value("Fac"); NodeItem fac = get_input_value("Fac");
NodeItem color = get_input_value("Color"); NodeItem color = get_input_value("Color");
return fac.blend(color, fac.one() - color); return fac.blend(color, fac.val(1.0f) - color);
} }
} // namespace blender::nodes::materialx } // namespace blender::nodes::materialx

View File

@ -8,6 +8,7 @@ namespace blender::nodes::materialx {
NodeItem MathNodeParser::compute() NodeItem MathNodeParser::compute()
{ {
/* TODO: implement */
return empty_value(); return empty_value();
} }

View File

@ -8,6 +8,7 @@ namespace blender::nodes::materialx {
NodeItem MixRGBNodeParser::compute() NodeItem MixRGBNodeParser::compute()
{ {
/* TODO: implement */
return empty_value(); return empty_value();
} }

View File

@ -10,6 +10,11 @@ namespace blender::nodes::materialx {
NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} 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) void NodeItem::set_input(const std::string &name, const NodeItem &item)
{ {
if (item.value) { if (item.value) {
@ -59,121 +64,141 @@ NodeItem::operator bool() const
return value || node; return value || node;
} }
NodeItem NodeItem::operator+(const NodeItem &other) NodeItem NodeItem::operator+(const NodeItem &other) const
{ {
return arithmetic(other, "add", [](float a, float b) { return a + b; }); return arithmetic(other, "add", [](float a, float b) { return a + b; });
} }
NodeItem NodeItem::operator-(const NodeItem &other) NodeItem NodeItem::operator-(const NodeItem &other) const
{ {
return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); return arithmetic(other, "subtract", [](float a, float b) { return a - b; });
} }
NodeItem NodeItem::operator*(const NodeItem &other) NodeItem NodeItem::operator*(const NodeItem &other) const
{ {
return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); return arithmetic(other, "multiply", [](float a, float b) { return a * b; });
} }
NodeItem NodeItem::operator/(const NodeItem &other) NodeItem NodeItem::operator/(const NodeItem &other) const
{ {
return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; });
} }
NodeItem NodeItem::min(const NodeItem &other) bool NodeItem::operator==(const NodeItem &other) const
{
if (node && node == other.node) {
return true;
}
/* TODO: implement */
return false;
}
NodeItem NodeItem::min(const NodeItem &other) const
{ {
return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); });
} }
NodeItem NodeItem::max(const NodeItem &other) NodeItem NodeItem::max(const NodeItem &other) const
{ {
return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); });
} }
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
{ {
return *this * a + (one() - *this) * b; return (val(1.0f) - *this) * a + *this * b;
} }
NodeItem NodeItem::to_color3() const NodeItem NodeItem::to_color3() const
{ {
NodeItem res(graph_); std::string t = type();
NodeItem res = empty();
if (value) { if (value) {
MaterialX::Color3 c; MaterialX::Color3 c;
if (value->isA<float>()) { if (t == "float") {
float v = value->asA<float>(); float v = value->asA<float>();
c = {v, v ,v}; c = {v, v, v};
} }
else if (value->isA<MaterialX::Color3>()) { else if (t == "color3") {
auto v = value->asA<MaterialX::Color3>(); auto v = value->asA<MaterialX::Color3>();
c = {v[0], v[1], v[2]}; c = {v[0], v[1], v[2]};
} }
else if (value->isA<MaterialX::Color4>()) { else if (t == "color4") {
auto v = value->asA<MaterialX::Color4>(); auto v = value->asA<MaterialX::Color4>();
c = {v[0], v[1], v[2]}; c = {v[0], v[1], v[2]};
} }
else if (value->isA<MaterialX::Vector3>()) { else if (t == "vector3") {
auto v = value->asA<MaterialX::Vector3>(); auto v = value->asA<MaterialX::Vector3>();
c = {v[0], v[1], v[2]}; c = {v[0], v[1], v[2]};
} }
else if (value->isA<MaterialX::Vector4>()) { else if (t == "vector4") {
auto v = value->asA<MaterialX::Vector4>(); auto v = value->asA<MaterialX::Vector4>();
c = {v[0], v[1], v[2]}; c = {v[0], v[1], v[2]};
} }
else { else {
/* Default color */ return res;
c = {0.0f, 0.0f, 0.0f};
} }
res.value = MaterialX::Value::createValue<MaterialX::Color3>(c); res.value = MaterialX::Value::createValue<MaterialX::Color3>(c);
} }
else if (node) { else if (node) {
if (t != "color3") {
return res;
}
res.node = node; res.node = node;
} }
return res; return res;
} }
NodeItem NodeItem::one() const bool NodeItem::is_numeric() const
{ {
NodeItem res(graph_); std::string t = type();
res = 1.0f; return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4");
return res;
} }
NodeItem NodeItem::arithmetic(const std::string &mx_category, std::function<float(float)> func) 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(); std::string t = value ? value->getTypeString() : node->getType();
NodeItem res(graph_); NodeItem res(graph_);
if (value) { if (value) {
if (value->isA<float>()) { if (t == "float") {
float v = value->asA<float>(); float v = value->asA<float>();
res.value = MaterialX::Value::createValue<float>(func(v)); res.value = MaterialX::Value::createValue<float>(func(v));
} }
else if (value->isA<MaterialX::Color3>()) { else if (t == "color3") {
auto v = value->asA<MaterialX::Color3>(); auto v = value->asA<MaterialX::Color3>();
res.value = MaterialX::Value::createValue<MaterialX::Color3>( res.value = MaterialX::Value::createValue<MaterialX::Color3>(
{func(v[0]), func(v[1]), func(v[2])}); {func(v[0]), func(v[1]), func(v[2])});
} }
else if (value->isA<MaterialX::Color4>()) { else if (t == "color4") {
auto v = value->asA<MaterialX::Color4>(); auto v = value->asA<MaterialX::Color4>();
res.value = MaterialX::Value::createValue<MaterialX::Color4>( res.value = MaterialX::Value::createValue<MaterialX::Color4>(
{func(v[0]), func(v[1]), func(v[2]), func(v[3])}); {func(v[0]), func(v[1]), func(v[2]), func(v[3])});
} }
else if (value->isA<MaterialX::Vector2>()) { else if (t == "vector2") {
auto v = value->asA<MaterialX::Vector2>(); auto v = value->asA<MaterialX::Vector2>();
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])}); res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
} }
else if (value->isA<MaterialX::Vector3>()) { else if (t == "vector3") {
auto v = value->asA<MaterialX::Vector3>(); auto v = value->asA<MaterialX::Vector3>();
res.value = MaterialX::Value::createValue<MaterialX::Vector3>( res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
{func(v[0]), func(v[1]), func(v[2])}); {func(v[0]), func(v[1]), func(v[2])});
} }
else if (value->isA<MaterialX::Vector4>()) { else if (t == "vector4") {
auto v = value->asA<MaterialX::Vector4>(); auto v = value->asA<MaterialX::Vector4>();
res.value = MaterialX::Value::createValue<MaterialX::Vector4>( res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
{func(v[0]), func(v[1]), func(v[2]), func(v[3])}); {func(v[0]), func(v[1]), func(v[2]), func(v[3])});
} }
else { else {
/* Nothing change */ BLI_assert_unreachable();
res.value = value;
} }
} }
else { else {
@ -185,64 +210,121 @@ NodeItem NodeItem::arithmetic(const std::string &mx_category, std::function<floa
NodeItem NodeItem::arithmetic(const NodeItem &other, NodeItem NodeItem::arithmetic(const NodeItem &other,
const std::string &mx_category, const std::string &mx_category,
std::function<float(float, float)> func) std::function<float(float, float)> func) const
{ {
std::string t1 = value ? value->getTypeString() : node->getType(); NodeItem res = empty();
std::string t2 = other.value ? other.value->getTypeString() : other.node->getType(); if (!is_numeric() || !other.is_numeric()) {
if (t1 != t2) { return res;
return *this;
} }
NodeItem res(graph_); std::string t1 = type();
std::string t2 = other.type();
if (value && other.value) { if (value && other.value) {
if (value->isA<float>()) { std::string t = t1;
float v1 = value->asA<float>(); auto val1 = value;
float v2 = other.value->asA<float>(); 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)); res.value = MaterialX::Value::createValue<float>(func(v1, v2));
} }
else if (value->isA<MaterialX::Color3>()) { else if (t == "color3") {
auto v1 = value->asA<MaterialX::Color3>(); auto v1 = val1->asA<MaterialX::Color3>();
auto v2 = other.value->asA<MaterialX::Color3>(); auto v2 = val2->asA<MaterialX::Color3>();
res.value = MaterialX::Value::createValue<MaterialX::Color3>( res.value = MaterialX::Value::createValue<MaterialX::Color3>(
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
} }
else if (value->isA<MaterialX::Color4>()) { else if (t == "color4") {
auto v1 = value->asA<MaterialX::Color4>(); auto v1 = val1->asA<MaterialX::Color4>();
auto v2 = other.value->asA<MaterialX::Color4>(); auto v2 = val2->asA<MaterialX::Color4>();
res.value = MaterialX::Value::createValue<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])}); {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
} }
else if (value->isA<MaterialX::Vector2>()) { else if (t == "vector2") {
auto v1 = value->asA<MaterialX::Vector2>(); auto v1 = val1->asA<MaterialX::Vector2>();
auto v2 = other.value->asA<MaterialX::Vector2>(); auto v2 = val2->asA<MaterialX::Vector2>();
res.value = MaterialX::Value::createValue<MaterialX::Vector2>( res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
{func(v1[0], v2[0]), func(v1[1], v2[1])}); {func(v1[0], v2[0]), func(v1[1], v2[1])});
} }
else if (value->isA<MaterialX::Vector3>()) { else if (t == "vector3") {
auto v1 = value->asA<MaterialX::Vector3>(); auto v1 = val1->asA<MaterialX::Vector3>();
auto v2 = other.value->asA<MaterialX::Vector3>(); auto v2 = val2->asA<MaterialX::Vector3>();
res.value = MaterialX::Value::createValue<MaterialX::Vector3>( res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
} }
else if (value->isA<MaterialX::Vector4>()) { else if (t == "vector4") {
auto v1 = value->asA<MaterialX::Vector4>(); auto v1 = val1->asA<MaterialX::Vector4>();
auto v2 = other.value->asA<MaterialX::Vector4>(); auto v2 = val2->asA<MaterialX::Vector4>();
res.value = MaterialX::Value::createValue<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])}); {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
} }
else { else {
/* default color */ BLI_assert_unreachable();
res.value = value;
} }
} }
else { else {
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t1); std::string t = t1;
res.set_input("in1", *this); auto val1 = *this;
res.set_input("in2", other); 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; 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, NodeParser::NodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph, const Depsgraph *depsgraph,
const Material *material, const Material *material,

View File

@ -24,6 +24,9 @@ class NodeItem {
NodeItem(MaterialX::GraphElement *graph); NodeItem(MaterialX::GraphElement *graph);
~NodeItem() = default; ~NodeItem() = default;
NodeItem empty() const;
template<class T> NodeItem val(const T &data) const;
template<class T> 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 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 NodeItem &item);
@ -31,39 +34,41 @@ class NodeItem {
void set_input(const std::string &name, const MaterialX::NodePtr node); void set_input(const std::string &name, const MaterialX::NodePtr node);
operator bool() const; operator bool() const;
template<class T> NodeItem &operator=(const T &value); NodeItem operator+(const NodeItem &other) const;
NodeItem operator+(const NodeItem &other); NodeItem operator-(const NodeItem &other) const;
NodeItem operator-(const NodeItem &other); NodeItem operator*(const NodeItem &other) const;
NodeItem operator*(const NodeItem &other); NodeItem operator/(const NodeItem &other) const;
NodeItem operator/(const NodeItem &other); bool operator==(const NodeItem &other) const;
NodeItem min(const NodeItem &other); NodeItem min(const NodeItem &other) const;
NodeItem max(const NodeItem &other); NodeItem max(const NodeItem &other) const;
NodeItem blend(const NodeItem &a, const NodeItem &b); NodeItem blend(const NodeItem &a, const NodeItem &b) const;
NodeItem to_color3() const; NodeItem to_color3() const;
NodeItem one() const; bool is_numeric() const;
std::string type() const;
private: private:
NodeItem arithmetic(const std::string &mx_category, std::function<float(float)> func); NodeItem arithmetic(const std::string &mx_category, std::function<float(float)> func) const;
NodeItem arithmetic(const NodeItem &other, NodeItem arithmetic(const NodeItem &other,
const std::string &mx_category, const std::string &mx_category,
std::function<float(float, float)> func); 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> template<class T>
void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type)
{ {
node->setInputValue(name, value, mx_type); node->setInputValue(name, value, mx_type);
} }
template<class T> NodeItem &NodeItem::operator=(const T &value)
{
this->value = MaterialX::Value::createValue<T>(value);
node = nullptr;
return *this;
}
class NodeParser { class NodeParser {
public: public:
MaterialX::GraphElement *graph; MaterialX::GraphElement *graph;
@ -91,11 +96,11 @@ class NodeParser {
}; };
#define DECLARE_PARSER(T) \ #define DECLARE_PARSER(T) \
class T : public NodeParser { \ class T : public NodeParser { \
public: \ public: \
using NodeParser::NodeParser; \ using NodeParser::NodeParser; \
NodeItem compute() override; \ NodeItem compute() override; \
}; };
DECLARE_PARSER(BSDFPrincipledNodeParser) DECLARE_PARSER(BSDFPrincipledNodeParser)
DECLARE_PARSER(InvertNodeParser) DECLARE_PARSER(InvertNodeParser)