Implement type conversion for NodeItem #9

Merged
Bogdan Nagirniak merged 12 commits from BogdanNagirniak/blender:matx-nodeitem-type into matx-export-material 2023-09-05 12:03:24 +02:00
5 changed files with 232 additions and 159 deletions
Showing only changes of commit dc5b3c9dba - Show all commits

View File

@ -12,6 +12,49 @@ namespace blender::nodes::materialx {
NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
NodeItem::Type NodeItem::type(const std::string &mx_type)
{
if (mx_type == "float") {
return Type::Float;
}
if (mx_type == "vector2") {
return Type::Vector2;
}
if (mx_type == "vector3") {
return Type::Vector3;
}
if (mx_type == "vector4") {
return Type::Vector4;
}
if (mx_type == "color3") {
return Type::Color3;
}
if (mx_type == "color4") {
return Type::Color4;
}
return Type::Other;
}
std::string NodeItem::type(Type mx_type)
{
switch (mx_type) {
case Type::Float:
return "float";
case Type::Vector2:
return "vector2";
case Type::Vector3:
return "vector3";
case Type::Vector4:
return "vector4";
case Type::Color3:
return "color3";
case Type::Color4:
return "color4";
default:
return "";
}
}
NodeItem NodeItem::empty() const NodeItem NodeItem::empty() const
{ {
return NodeItem(graph_); return NodeItem(graph_);
@ -135,31 +178,28 @@ bool NodeItem::operator==(const NodeItem &other) const
return false; return false;
} }
std::string mx_type; Type mx_type;
auto val1 = value; auto val1 = value;
auto val2 = other.value; auto val2 = other.value;
if (!adjust_types(val1, val2, mx_type)) { if (!adjust_types(val1, val2, mx_type)) {
return false; return false;
} }
if (mx_type == "float") { switch (mx_type) {
return val1->asA<float>() == val2->asA<float>(); case Type::Vector2:
return val1->asA<MaterialX::Vector2>() == val2->asA<MaterialX::Vector2>();
case Type::Vector3:
return val1->asA<MaterialX::Vector3>() == val2->asA<MaterialX::Vector3>();
case Type::Vector4:
return val1->asA<MaterialX::Vector4>() == val2->asA<MaterialX::Vector4>();
case Type::Float:
return val1->asA<float>() == val2->asA<float>();
case Type::Color3:
return val1->asA<MaterialX::Color3>() == val2->asA<MaterialX::Color3>();
case Type::Color4:
return val1->asA<MaterialX::Color4>() == val2->asA<MaterialX::Color4>();
default:
break;
} }
if (mx_type == "color3") {
return val1->asA<MaterialX::Color3>() == val2->asA<MaterialX::Color3>();
}
if (mx_type == "color4") {
return val1->asA<MaterialX::Color4>() == val2->asA<MaterialX::Color4>();
}
if (mx_type == "vector2") {
return val1->asA<MaterialX::Vector2>() == val2->asA<MaterialX::Vector2>();
}
if (mx_type == "vector3") {
return val1->asA<MaterialX::Vector3>() == val2->asA<MaterialX::Vector3>();
}
if (mx_type == "vector4") {
return val1->asA<MaterialX::Vector4>() == val2->asA<MaterialX::Vector4>();
}
return false; return false;
} }
@ -197,33 +237,40 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const
{ {
NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; });
if (d.value) { if (d.value) {
std::string mx_type = d.type(); Type mx_type = d.type();
float f = 0.0f; float f = 0.0f;
if (mx_type == "float") { switch (mx_type) {
f = value->asA<float>(); case Type::Float: {
} f = value->asA<float>();
else if (mx_type == "color3") { break;
auto v = value->asA<MaterialX::Color3>(); }
f = v[0] + v[1] + v[2]; case Type::Vector2: {
} auto v = value->asA<MaterialX::Vector2>();
else if (mx_type == "color4") { f = v[0] + v[1];
auto v = value->asA<MaterialX::Color4>(); break;
f = v[0] + v[1] + v[2] + v[3]; }
} case Type::Vector3: {
else if (mx_type == "vector2") { auto v = value->asA<MaterialX::Vector3>();
auto v = value->asA<MaterialX::Vector2>(); f = v[0] + v[1] + v[2];
f = v[0] + v[1]; break;
} }
else if (mx_type == "vector3") { case Type::Vector4: {
auto v = value->asA<MaterialX::Vector3>(); auto v = value->asA<MaterialX::Vector4>();
f = v[0] + v[1] + v[2]; f = v[0] + v[1] + v[2] + v[3];
} break;
else if (mx_type == "vector4") { }
auto v = value->asA<MaterialX::Vector4>(); case Type::Color3: {
f = v[0] + v[1] + v[2] + v[3]; auto v = value->asA<MaterialX::Color3>();
} f = v[0] + v[1] + v[2];
else { break;
BLI_assert_unreachable(); }
case Type::Color4: {
auto v = value->asA<MaterialX::Color4>();
f = v[0] + v[1] + v[2] + v[3];
break;
}
default:
BLI_assert_unreachable();
} }
d.value = MaterialX::Value::createValue(f); d.value = MaterialX::Value::createValue(f);
} }
@ -246,13 +293,13 @@ NodeItem NodeItem::if_else(const std::string &condition,
} }
NodeItem res = empty(); NodeItem res = empty();
if (type() != "float" || other.type() != "float") { if (type() != Type::Float || other.type() != Type::Float) {
return res; return res;
} }
auto val1 = if_val; auto val1 = if_val;
auto val2 = else_val; auto val2 = else_val;
std::string mx_type; Type mx_type;
if (!adjust_types(val1, val2, mx_type)) { if (!adjust_types(val1, val2, mx_type)) {
return res; return res;
} }
@ -279,7 +326,7 @@ NodeItem NodeItem::if_else(const std::string &condition,
res = func(value->asA<float>(), other.value->asA<float>()) ? val1 : val2; res = func(value->asA<float>(), other.value->asA<float>()) ? val1 : val2;
} }
else { else {
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(mx_type));
res.set_input("value1", *this); res.set_input("value1", *this);
res.set_input("value2", other); res.set_input("value2", other);
res.set_input("in1", val1); res.set_input("in1", val1);
@ -376,37 +423,43 @@ NodeItem NodeItem::exp() const
NodeItem NodeItem::to_color3() const NodeItem NodeItem::to_color3() const
{ {
std::string mx_type = type(); Type mx_type = type();
NodeItem res = empty(); NodeItem res = empty();
if (value) { if (value) {
MaterialX::Color3 c; MaterialX::Color3 c;
if (mx_type == "float") { switch (mx_type) {
float v = value->asA<float>(); case Type::Float: {
c = {v, v, v}; float v = value->asA<float>();
} c = {v, v, v};
else if (mx_type == "color3") { break;
auto v = value->asA<MaterialX::Color3>(); }
c = {v[0], v[1], v[2]}; case Type::Color3: {
BogdanNagirniak marked this conversation as resolved
Review

Should Integer be here?

Should `Integer` be here?
Review

Discussed: let it be here

Discussed: let it be here
} auto v = value->asA<MaterialX::Color3>();
else if (mx_type == "color4") { c = {v[0], v[1], v[2]};
auto v = value->asA<MaterialX::Color4>(); break;
c = {v[0], v[1], v[2]}; }
} case Type::Color4: {
else if (mx_type == "vector3") { auto v = value->asA<MaterialX::Color4>();
auto v = value->asA<MaterialX::Vector3>(); c = {v[0], v[1], v[2]};
c = {v[0], v[1], v[2]}; break;
} }
else if (mx_type == "vector4") { case Type::Vector3: {
auto v = value->asA<MaterialX::Vector4>(); auto v = value->asA<MaterialX::Vector3>();
c = {v[0], v[1], v[2]}; c = {v[0], v[1], v[2]};
} break;
else { }
return res; case Type::Vector4: {
auto v = value->asA<MaterialX::Vector4>();
c = {v[0], v[1], v[2]};
break;
}
default:
return res;
} }
res.value = MaterialX::Value::createValue<MaterialX::Color3>(c); res.value = MaterialX::Value::createValue<MaterialX::Color3>(c);
} }
else if (node) { else if (node) {
if (mx_type != "color3") { if (mx_type !=Type::Color3) {
return res; return res;
} }
res.node = node; res.node = node;
@ -416,13 +469,18 @@ NodeItem NodeItem::to_color3() const
bool NodeItem::is_numeric() const bool NodeItem::is_numeric() const
{ {
std::string t = type(); return type() >= Type::Float;
return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4");
} }
std::string NodeItem::type() const NodeItem::Type NodeItem::type() const
{ {
return value ? value->getTypeString() : node->getType(); if (value) {
return type(value->getTypeString());
}
if (node) {
return type(node->getType());
}
return Type::Empty;
} }
NodeItem NodeItem::arithmetic(const std::string &mx_category, NodeItem NodeItem::arithmetic(const std::string &mx_category,
@ -483,7 +541,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
return res; return res;
} }
std::string mx_type; Type mx_type;
if (value && other.value) { if (value && other.value) {
auto val1 = value; auto val1 = value;
auto val2 = other.value; auto val2 = other.value;
@ -491,43 +549,50 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
return res; return res;
} }
if (mx_type == "float") { switch (mx_type) {
float v1 = val1->asA<float>(); case Type::Float: {
float v2 = val2->asA<float>(); float v1 = val1->asA<float>();
res.value = MaterialX::Value::createValue<float>(func(v1, v2)); float v2 = val2->asA<float>();
} res.value = MaterialX::Value::createValue<float>(func(v1, v2));
else if (mx_type == "color3") { break;
auto v1 = val1->asA<MaterialX::Color3>(); }
auto v2 = val2->asA<MaterialX::Color3>(); case Type::Color3: {
res.value = MaterialX::Value::createValue<MaterialX::Color3>( auto v1 = val1->asA<MaterialX::Color3>();
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); auto v2 = val2->asA<MaterialX::Color3>();
} res.value = MaterialX::Value::createValue<MaterialX::Color3>(
else if (mx_type == "color4") { {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
auto v1 = val1->asA<MaterialX::Color4>(); break;
auto v2 = val2->asA<MaterialX::Color4>(); }
res.value = MaterialX::Value::createValue<MaterialX::Color4>( case Type::Color4: {
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); auto v1 = val1->asA<MaterialX::Color4>();
} auto v2 = val2->asA<MaterialX::Color4>();
else if (mx_type == "vector2") { res.value = MaterialX::Value::createValue<MaterialX::Color4>(
auto v1 = val1->asA<MaterialX::Vector2>(); {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
auto v2 = val2->asA<MaterialX::Vector2>(); break;
res.value = MaterialX::Value::createValue<MaterialX::Vector2>( }
{func(v1[0], v2[0]), func(v1[1], v2[1])}); case Type::Vector2: {
} auto v1 = val1->asA<MaterialX::Vector2>();
else if (mx_type == "vector3") { auto v2 = val2->asA<MaterialX::Vector2>();
auto v1 = val1->asA<MaterialX::Vector3>(); res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
auto v2 = val2->asA<MaterialX::Vector3>(); {func(v1[0], v2[0]), func(v1[1], v2[1])});
res.value = MaterialX::Value::createValue<MaterialX::Vector3>( break;
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); }
} case Type::Vector3: {
else if (mx_type == "vector4") { auto v1 = val1->asA<MaterialX::Vector3>();
auto v1 = val1->asA<MaterialX::Vector4>(); auto v2 = val2->asA<MaterialX::Vector3>();
auto v2 = val2->asA<MaterialX::Vector4>(); res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
res.value = MaterialX::Value::createValue<MaterialX::Vector4>( {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]), func(v1[3], v2[3])}); break;
} }
else { case Type::Vector4: {
BLI_assert_unreachable(); 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])});
break;
}
default:
BLI_assert_unreachable();
} }
} }
else { else {
@ -537,50 +602,51 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
return res; return res;
} }
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(mx_type));
res.set_input("in1", val1); res.set_input("in1", val1);
res.set_input("in2", val2); res.set_input("in2", val2);
} }
return res; return res;
} }
MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string mx_type) MaterialX::ValuePtr NodeItem::float_to_type(float v, Type mx_type)
{ {
if (mx_type == "float") { MaterialX::ValuePtr res;
return MaterialX::Value::createValue<float>(v); switch (mx_type) {
case Type::Float:
res = MaterialX::Value::createValue<float>(v);
break;
case Type::Vector2:
res = MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
break;
case Type::Vector3:
res = MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
break;
case Type::Vector4:
res = MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, v});
break;
case Type::Color3:
res = MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
break;
case Type::Color4:
res = MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, v});
break;
default:
BLI_assert_unreachable();
} }
if (mx_type == "color3") { return res;
return MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
}
if (mx_type == "color4") {
return MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
}
if (mx_type == "vector2") {
return MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
}
if (mx_type == "vector3") {
return MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
}
if (mx_type == "vector4") {
return MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
}
BLI_assert_unreachable();
return nullptr;
} }
bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, Type &mx_type)
MaterialX::ValuePtr &val2,
std::string &mx_type)
{ {
std::string t1 = val1->getTypeString(); Type t1 = type(val1->getTypeString());
std::string t2 = val2->getTypeString(); Type t2 = type(val2->getTypeString());
if (t1 != t2) { if (t1 != t2) {
if (t1 == "float") { if (t1 == Type::Float) {
val1 = float_to_type(val1->asA<float>(), t2); val1 = float_to_type(val1->asA<float>(), t2);
mx_type = t2; mx_type = t2;
} }
else if (t2 == "float") { else if (t2 == Type::Float) {
val2 = float_to_type(val2->asA<float>(), t1); val2 = float_to_type(val2->asA<float>(), t1);
mx_type = t1; mx_type = t1;
} }
@ -594,16 +660,16 @@ bool NodeItem::adjust_types(MaterialX::ValuePtr &val1,
return true; return true;
} }
bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type) bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, Type &mx_type)
{ {
std::string t1 = val1.type(); Type t1 = val1.type();
std::string t2 = val2.type(); Type t2 = val2.type();
if (t1 != t2) { if (t1 != t2) {
if (val1.value && t1 == "float") { if (val1.value && t1 == Type::Float) {
val1.value = float_to_type(val1.value->asA<float>(), t2); val1.value = float_to_type(val1.value->asA<float>(), t2);
mx_type = t2; mx_type = t2;
} }
else if (val2.value && t2 == "float") { else if (val2.value && t2 == Type::Float) {
val2.value = float_to_type(val2.value->asA<float>(), t1); val2.value = float_to_type(val2.value->asA<float>(), t1);
mx_type = t1; mx_type = t1;
} }

View File

@ -9,6 +9,9 @@
namespace blender::nodes::materialx { namespace blender::nodes::materialx {
class NodeItem { class NodeItem {
public:
enum class Type { Empty = 0, Other, Float, Vector2, Vector3, Vector4, Color3, Color4 };
public: public:
MaterialX::ValuePtr value; MaterialX::ValuePtr value;
MaterialX::NodePtr node; MaterialX::NodePtr node;
@ -20,6 +23,9 @@ class NodeItem {
NodeItem(MaterialX::GraphElement *graph); NodeItem(MaterialX::GraphElement *graph);
~NodeItem() = default; ~NodeItem() = default;
static Type type(const std::string &mx_type);
static std::string type(Type mx_type);
NodeItem empty() const; NodeItem empty() const;
template<class T> NodeItem val(const T &data) const; template<class T> NodeItem val(const T &data) const;
@ -75,19 +81,17 @@ class NodeItem {
NodeItem to_color3() const; NodeItem to_color3() const;
bool is_numeric() const; bool is_numeric() const;
std::string type() const; Type type() const;
private: private:
NodeItem arithmetic(const std::string &mx_category, std::function<float(float)> func) const; 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) const; std::function<float(float, float)> func) const;
static MaterialX::ValuePtr float_to_type(float v, std::string mx_type); static MaterialX::ValuePtr float_to_type(float v, Type mx_type);
/* Functions for adjusting values to make equal types */ /* Functions for adjusting values to make equal types */
static bool adjust_types(MaterialX::ValuePtr &val1, static bool adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, Type &mx_type);
MaterialX::ValuePtr &val2, static bool adjust_types(NodeItem &val1, NodeItem &val2, Type &mx_type);
std::string &mx_type);
static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type);
}; };
template<class T> NodeItem NodeItem::val(const T &data) const template<class T> NodeItem NodeItem::val(const T &data) const

View File

@ -74,17 +74,20 @@ NodeItem NodeParser::get_input_default(const bNodeSocket &socket)
case SOCK_FLOAT: { case SOCK_FLOAT: {
float v = socket.default_value_typed<bNodeSocketValueFloat>()->value; float v = socket.default_value_typed<bNodeSocketValueFloat>()->value;
res.value = MaterialX::Value::createValue<float>(v); res.value = MaterialX::Value::createValue<float>(v);
} break; break;
}
case SOCK_VECTOR: { case SOCK_VECTOR: {
const float *v = socket.default_value_typed<bNodeSocketValueVector>()->value; const float *v = socket.default_value_typed<bNodeSocketValueVector>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Vector3>( res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
MaterialX::Vector3(v[0], v[1], v[2])); MaterialX::Vector3(v[0], v[1], v[2]));
} break; break;
}
case SOCK_RGBA: { case SOCK_RGBA: {
const float *v = socket.default_value_typed<bNodeSocketValueRGBA>()->value; const float *v = socket.default_value_typed<bNodeSocketValueRGBA>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Color4>( res.value = MaterialX::Value::createValue<MaterialX::Color4>(
MaterialX::Color4(v[0], v[1], v[2], v[3])); MaterialX::Color4(v[0], v[1], v[2], v[3]));
} break; break;
}
default: { default: {
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type); CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type);
} }

View File

@ -12,7 +12,7 @@ NodeItem TexCheckerNodeParser::compute()
NodeItem color1 = get_input_value("Color1"); NodeItem color1 = get_input_value("Color1");
NodeItem color2 = get_input_value("Color2"); NodeItem color2 = get_input_value("Color2");
if (scale.value && scale.type() == "float") { if (scale.value && scale.type() == NodeItem::Type::Float) {
float v = scale.value->asA<float>(); float v = scale.value->asA<float>();
scale = value(MaterialX::Vector2(v, v)); scale = value(MaterialX::Vector2(v, v));
} }

View File

@ -12,7 +12,7 @@ NodeItem TexNoiseNodeParser::compute()
NodeItem detail = get_input_value("Detail"); NodeItem detail = get_input_value("Detail");
NodeItem lacunarity = get_input_value("Lacunarity"); NodeItem lacunarity = get_input_value("Lacunarity");
if (detail.value && detail.type() == "float") { if (detail.value && detail.type() == NodeItem::Type::Float) {
detail = value(int(detail.value->asA<float>())); detail = value(int(detail.value->asA<float>()));
} }