forked from blender/blender
Implement type conversion for NodeItem #9
@ -15,12 +15,8 @@ NodeItem BSDFPrincipledNodeParser::compute()
|
|||||||
NodeItem base_color = get_input_value("Base Color");
|
NodeItem base_color = get_input_value("Base Color");
|
||||||
|
|
||||||
NodeItem subsurface = get_input_value("Subsurface");
|
NodeItem subsurface = get_input_value("Subsurface");
|
||||||
NodeItem subsurface_radius = empty();
|
NodeItem subsurface_radius = get_input_value("Subsurface Radius");
|
||||||
NodeItem subsurface_color = empty();
|
NodeItem subsurface_color = get_input_value("Subsurface Color");
|
||||||
if (subsurface != zero) {
|
|
||||||
subsurface_radius = get_input_value("Subsurface Radius");
|
|
||||||
subsurface_color = get_input_value("Subsurface Color");
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem metallic = get_input_value("Metallic");
|
NodeItem metallic = get_input_value("Metallic");
|
||||||
NodeItem specular = get_input_value("Specular");
|
NodeItem specular = get_input_value("Specular");
|
||||||
@ -70,7 +66,7 @@ NodeItem BSDFPrincipledNodeParser::compute()
|
|||||||
/* Creating standard_surface */
|
/* Creating standard_surface */
|
||||||
NodeItem res = create_node("standard_surface", "surfaceshader");
|
NodeItem res = create_node("standard_surface", "surfaceshader");
|
||||||
res.set_input("base", 1.0, "float");
|
res.set_input("base", 1.0, "float");
|
||||||
res.set_input("base_color", base_color.to_color3());
|
res.set_input("base_color", base_color, NodeItem::Type::Color3);
|
||||||
res.set_input("diffuse_roughness", roughness);
|
res.set_input("diffuse_roughness", roughness);
|
||||||
if (normal) {
|
if (normal) {
|
||||||
res.set_input("normal", normal);
|
res.set_input("normal", normal);
|
||||||
@ -85,7 +81,7 @@ NodeItem BSDFPrincipledNodeParser::compute()
|
|||||||
|
|
||||||
if (specular != zero) {
|
if (specular != zero) {
|
||||||
res.set_input("specular", specular);
|
res.set_input("specular", specular);
|
||||||
res.set_input("specular_color", base_color.to_color3());
|
res.set_input("specular_color", base_color, NodeItem::Type::Color3);
|
||||||
res.set_input("specular_roughness", roughness);
|
res.set_input("specular_roughness", roughness);
|
||||||
res.set_input("specular_IOR", ior);
|
res.set_input("specular_IOR", ior);
|
||||||
if (anisotropic) {
|
if (anisotropic) {
|
||||||
@ -98,28 +94,26 @@ NodeItem BSDFPrincipledNodeParser::compute()
|
|||||||
|
|
||||||
if (transmission != zero) {
|
if (transmission != zero) {
|
||||||
res.set_input("transmission", transmission);
|
res.set_input("transmission", transmission);
|
||||||
res.set_input("transmission_color", base_color.to_color3());
|
res.set_input("transmission_color", base_color, NodeItem::Type::Color3);
|
||||||
res.set_input("transmission_extra_roughness", transmission_roughness);
|
res.set_input("transmission_extra_roughness", transmission_roughness);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subsurface != zero) {
|
|
||||||
res.set_input("subsurface", subsurface);
|
res.set_input("subsurface", subsurface);
|
||||||
res.set_input("subsurface_color", subsurface_color);
|
res.set_input("subsurface_color", subsurface_color);
|
||||||
res.set_input("subsurface_radius", subsurface_radius);
|
res.set_input("subsurface_radius", subsurface_radius);
|
||||||
if (anisotropic) {
|
if (anisotropic) {
|
||||||
res.set_input("subsurface_anisotropy", anisotropic);
|
res.set_input("subsurface_anisotropy", anisotropic);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (sheen != zero) {
|
if (sheen != zero) {
|
||||||
res.set_input("sheen", sheen);
|
res.set_input("sheen", sheen);
|
||||||
res.set_input("sheen_color", base_color.to_color3());
|
res.set_input("sheen_color", base_color, NodeItem::Type::Color3);
|
||||||
res.set_input("sheen_roughness", roughness);
|
res.set_input("sheen_roughness", roughness);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearcoat != zero) {
|
if (clearcoat != zero) {
|
||||||
res.set_input("coat", clearcoat);
|
res.set_input("coat", clearcoat);
|
||||||
res.set_input("coat_color", base_color.to_color3());
|
res.set_input("coat_color", base_color, NodeItem::Type::Color3);
|
||||||
res.set_input("coat_roughness", clearcoat_roughness);
|
res.set_input("coat_roughness", clearcoat_roughness);
|
||||||
res.set_input("coat_IOR", ior);
|
res.set_input("coat_IOR", ior);
|
||||||
if (anisotropic) {
|
if (anisotropic) {
|
||||||
@ -131,7 +125,7 @@ NodeItem BSDFPrincipledNodeParser::compute()
|
|||||||
|
|
||||||
if (emission != zero) {
|
if (emission != zero) {
|
||||||
res.set_input("emission", emission_strength);
|
res.set_input("emission", emission_strength);
|
||||||
res.set_input("emission_color", emission);
|
res.set_input("emission_color", emission, NodeItem::Type::Color3);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#include "node_parser.h"
|
|
||||||
#include "../material.h"
|
#include "../material.h"
|
||||||
|
#include "node_parser.h"
|
||||||
|
|
||||||
namespace blender::nodes::materialx {
|
namespace blender::nodes::materialx {
|
||||||
|
|
||||||
@ -109,10 +109,10 @@ NodeItem MathNodeParser::compute()
|
|||||||
res = x.max(y);
|
res = x.max(y);
|
||||||
break;
|
break;
|
||||||
case NODE_MATH_LESS_THAN:
|
case NODE_MATH_LESS_THAN:
|
||||||
res = x.if_else("<", y, value(1.0f), value(0.0f));
|
res = x.if_else(NodeItem::CompareOp::Less, y, value(1.0f), value(0.0f));
|
||||||
break;
|
break;
|
||||||
case NODE_MATH_GREATER_THAN:
|
case NODE_MATH_GREATER_THAN:
|
||||||
res = x.if_else(">", y, value(1.0f), value(0.0f));
|
res = x.if_else(NodeItem::CompareOp::Greater, y, value(1.0f), value(0.0f));
|
||||||
break;
|
break;
|
||||||
case NODE_MATH_MODULO:
|
case NODE_MATH_MODULO:
|
||||||
res = x % y;
|
res = x % y;
|
||||||
@ -138,7 +138,7 @@ NodeItem MathNodeParser::compute()
|
|||||||
CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op);
|
CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op);
|
||||||
break;
|
break;
|
||||||
case NODE_MATH_COMPARE:
|
case NODE_MATH_COMPARE:
|
||||||
res = z.if_else("<", (x - y).abs(), value(1.0f), value(0.0f));
|
res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), value(1.0f), value(0.0f));
|
||||||
break;
|
break;
|
||||||
case NODE_MATH_MULTIPLY_ADD:
|
case NODE_MATH_MULTIPLY_ADD:
|
||||||
res = x * y + z;
|
res = x * y + z;
|
||||||
|
@ -12,73 +12,6 @@ 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,
|
|
||||||
const std::string &output_name)
|
|
||||||
{
|
|
||||||
if (item.value) {
|
|
||||||
set_input(name, item.value);
|
|
||||||
}
|
|
||||||
else if (item.node) {
|
|
||||||
set_input(name, item.node, output_name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value)
|
|
||||||
{
|
|
||||||
std::string mx_type = value->getTypeString();
|
|
||||||
if (mx_type == "float") {
|
|
||||||
set_input(name, value->asA<float>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "integer") {
|
|
||||||
set_input(name, value->asA<int>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "vector2") {
|
|
||||||
set_input(name, value->asA<MaterialX::Vector2>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "vector3") {
|
|
||||||
set_input(name, value->asA<MaterialX::Vector3>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "vector4") {
|
|
||||||
set_input(name, value->asA<MaterialX::Vector4>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "color3") {
|
|
||||||
set_input(name, value->asA<MaterialX::Color3>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "color4") {
|
|
||||||
set_input(name, value->asA<MaterialX::Color4>(), mx_type);
|
|
||||||
}
|
|
||||||
else if (mx_type == "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,
|
|
||||||
const std::string &output_name)
|
|
||||||
{
|
|
||||||
this->node->setConnectedNode(name, node);
|
|
||||||
if (output_name != "") {
|
|
||||||
this->node->setConnectedOutput("in1", node->getOutput(output_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeItem::add_output(const std::string &name, const std::string &mx_type)
|
|
||||||
{
|
|
||||||
node->addOutput(name, mx_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem::operator bool() const
|
NodeItem::operator bool() const
|
||||||
{
|
{
|
||||||
return value || node;
|
return value || node;
|
||||||
@ -135,32 +68,13 @@ bool NodeItem::operator==(const NodeItem &other) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mx_type;
|
NodeItem item1 = *this;
|
||||||
auto val1 = value;
|
NodeItem item2 = other;
|
||||||
auto val2 = other.value;
|
Type to_type = adjust_types(item1, item2);
|
||||||
if (!adjust_types(val1, val2, mx_type)) {
|
if (to_type == Type::Empty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mx_type == "float") {
|
return item1.value->getValueString() == item2.value->getValueString();
|
||||||
return val1->asA<float>() == val2->asA<float>();
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodeItem::operator!=(const NodeItem &other) const
|
bool NodeItem::operator!=(const NodeItem &other) const
|
||||||
@ -197,32 +111,39 @@ 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) {
|
||||||
|
case Type::Float: {
|
||||||
f = value->asA<float>();
|
f = value->asA<float>();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "color3") {
|
case Type::Vector2: {
|
||||||
auto v = value->asA<MaterialX::Color3>();
|
|
||||||
f = v[0] + v[1] + v[2];
|
|
||||||
}
|
|
||||||
else if (mx_type == "color4") {
|
|
||||||
auto v = value->asA<MaterialX::Color4>();
|
|
||||||
f = v[0] + v[1] + v[2] + v[3];
|
|
||||||
}
|
|
||||||
else if (mx_type == "vector2") {
|
|
||||||
auto v = value->asA<MaterialX::Vector2>();
|
auto v = value->asA<MaterialX::Vector2>();
|
||||||
f = v[0] + v[1];
|
f = v[0] + v[1];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "vector3") {
|
case Type::Vector3: {
|
||||||
auto v = value->asA<MaterialX::Vector3>();
|
auto v = value->asA<MaterialX::Vector3>();
|
||||||
f = v[0] + v[1] + v[2];
|
f = v[0] + v[1] + v[2];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "vector4") {
|
case Type::Vector4: {
|
||||||
auto v = value->asA<MaterialX::Vector4>();
|
auto v = value->asA<MaterialX::Vector4>();
|
||||||
f = v[0] + v[1] + v[2] + v[3];
|
f = v[0] + v[1] + v[2] + v[3];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else {
|
case Type::Color3: {
|
||||||
|
auto v = value->asA<MaterialX::Color3>();
|
||||||
|
f = v[0] + v[1] + v[2];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Color4: {
|
||||||
|
auto v = value->asA<MaterialX::Color4>();
|
||||||
|
f = v[0] + v[1] + v[2] + v[3];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
d.value = MaterialX::Value::createValue(f);
|
d.value = MaterialX::Value::createValue(f);
|
||||||
@ -230,65 +151,6 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::if_else(const std::string &condition,
|
|
||||||
const NodeItem &other,
|
|
||||||
const NodeItem &if_val,
|
|
||||||
const NodeItem &else_val) const
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem res = empty();
|
|
||||||
if (type() != "float" || other.type() != "float") {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto val1 = if_val;
|
|
||||||
auto val2 = else_val;
|
|
||||||
std::string mx_type;
|
|
||||||
if (!adjust_types(val1, val2, mx_type)) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::function<bool(float, float)> func = nullptr;
|
|
||||||
std::string mx_category;
|
|
||||||
if (condition == ">") {
|
|
||||||
mx_category = "ifgreater";
|
|
||||||
func = [](float a, float b) { return a > b; };
|
|
||||||
}
|
|
||||||
else if (condition == ">=") {
|
|
||||||
mx_category = "ifgreatereq";
|
|
||||||
func = [](float a, float b) { return a >= b; };
|
|
||||||
}
|
|
||||||
else if (condition == "==") {
|
|
||||||
mx_category = "ifequal";
|
|
||||||
func = [](float a, float b) { return a == b; };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value && other.value) {
|
|
||||||
res = func(value->asA<float>(), other.value->asA<float>()) ? val1 : val2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
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);
|
|
||||||
res.set_input("in2", val2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
|
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
|
||||||
{
|
{
|
||||||
return (val(1.0f) - *this) * a + *this * b;
|
return (val(1.0f) - *this) * a + *this * b;
|
||||||
@ -374,247 +236,528 @@ NodeItem NodeItem::exp() const
|
|||||||
return arithmetic("exp", [](float a) { return std::expf(a); });
|
return arithmetic("exp", [](float a) { return std::expf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::to_color3() const
|
NodeItem NodeItem::convert(Type to_type) const
|
||||||
{
|
{
|
||||||
std::string mx_type = type();
|
Type from_type = type();
|
||||||
BogdanNagirniak marked this conversation as resolved
Outdated
|
|||||||
NodeItem res = empty();
|
if (from_type == to_type) {
|
||||||
if (value) {
|
return *this;
|
||||||
MaterialX::Color3 c;
|
|
||||||
if (mx_type == "float") {
|
|
||||||
float v = value->asA<float>();
|
|
||||||
c = {v, v, v};
|
|
||||||
}
|
}
|
||||||
else if (mx_type == "color3") {
|
if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) {
|
||||||
auto v = value->asA<MaterialX::Color3>();
|
|
||||||
c = {v[0], v[1], v[2]};
|
|
||||||
}
|
|
||||||
else if (mx_type == "color4") {
|
|
||||||
auto v = value->asA<MaterialX::Color4>();
|
|
||||||
c = {v[0], v[1], v[2]};
|
|
||||||
}
|
|
||||||
else if (mx_type == "vector3") {
|
|
||||||
auto v = value->asA<MaterialX::Vector3>();
|
|
||||||
c = {v[0], v[1], v[2]};
|
|
||||||
}
|
|
||||||
else if (mx_type == "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 (mx_type != "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();
|
return empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string t = value ? value->getTypeString() : node->getType();
|
if (to_type == Type::Float) {
|
||||||
NodeItem res(graph_);
|
/* TODO: Convert to float, <extract> should be used */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converting types which requires > 1 iteration */
|
||||||
|
switch (from_type) {
|
||||||
|
case Type::Vector2:
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector4:
|
||||||
|
return convert(Type::Vector3).convert(Type::Vector4);
|
||||||
|
case Type::Color3:
|
||||||
|
return convert(Type::Vector3).convert(Type::Color3);
|
||||||
|
case Type::Color4:
|
||||||
|
return convert(Type::Vector3).convert(Type::Color3).convert(Type::Color4);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type::Vector3:
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Color4:
|
||||||
|
return convert(Type::Color3).convert(Type::Color4);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type::Vector4:
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector2:
|
||||||
|
return convert(Type::Vector3).convert(Type::Vector2);
|
||||||
|
case Type::Color3:
|
||||||
|
return convert(Type::Vector3).convert(Type::Color3);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type::Color3:
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector2:
|
||||||
|
return convert(Type::Vector3).convert(Type::Vector2);
|
||||||
|
case Type::Vector4:
|
||||||
|
return convert(Type::Vector3).convert(Type::Vector4);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type::Color4:
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector2:
|
||||||
|
return convert(Type::Vector4).convert(Type::Vector3).convert(Type::Vector2);
|
||||||
|
case Type::Vector3:
|
||||||
|
return convert(Type::Vector4).convert(Type::Vector3);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converting 1 iteration types */
|
||||||
|
NodeItem res = empty();
|
||||||
if (value) {
|
if (value) {
|
||||||
if (t == "float") {
|
switch (from_type) {
|
||||||
|
case Type::Float: {
|
||||||
float v = value->asA<float>();
|
float v = value->asA<float>();
|
||||||
res.value = MaterialX::Value::createValue<float>(func(v));
|
switch (to_type) {
|
||||||
|
case Type::Vector2:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
|
||||||
|
break;
|
||||||
|
case Type::Vector3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
|
||||||
|
break;
|
||||||
|
case Type::Vector4:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
|
||||||
|
break;
|
||||||
|
case Type::Color3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
|
||||||
|
break;
|
||||||
|
case Type::Color4:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
else if (t == "color3") {
|
break;
|
||||||
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") {
|
case Type::Vector2: {
|
||||||
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>();
|
auto v = value->asA<MaterialX::Vector2>();
|
||||||
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
|
switch (to_type) {
|
||||||
|
case Type::Vector3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], 0.0f});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
else if (t == "vector3") {
|
break;
|
||||||
|
}
|
||||||
|
case Type::Vector3: {
|
||||||
auto v = value->asA<MaterialX::Vector3>();
|
auto v = value->asA<MaterialX::Vector3>();
|
||||||
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
switch (to_type) {
|
||||||
{func(v[0]), func(v[1]), func(v[2])});
|
case Type::Vector2:
|
||||||
}
|
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({v[0], v[1]});
|
||||||
else if (t == "vector4") {
|
break;
|
||||||
auto v = value->asA<MaterialX::Vector4>();
|
case Type::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])});
|
{v[0], v[1], v[2], 0.0f});
|
||||||
|
break;
|
||||||
|
case Type::Color3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>({v[0], v[1], v[2]});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
else {
|
break;
|
||||||
|
}
|
||||||
|
case Type::Vector4: {
|
||||||
|
auto v = value->asA<MaterialX::Vector4>();
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], v[2]});
|
||||||
|
break;
|
||||||
|
case Type::Color4:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color4>({v[0], v[1], v[2], v[3]});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Color3: {
|
||||||
|
auto v = value->asA<MaterialX::Color3>();
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], v[2]});
|
||||||
|
break;
|
||||||
|
case Type::Color4:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color4>({v[0], v[1], v[2], 1.0f});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Color4: {
|
||||||
|
auto v = value->asA<MaterialX::Color4>();
|
||||||
|
switch (to_type) {
|
||||||
|
case Type::Vector4:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
||||||
|
{v[0], v[1], v[2], v[3]});
|
||||||
|
break;
|
||||||
|
case Type::Color3:
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>({v[0], v[1], v[2]});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t);
|
res.node = graph_->addNode("convert", MaterialX::EMPTY_STRING, type(to_type));
|
||||||
|
res.set_input("in", *this);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::if_else(CompareOp op,
|
||||||
|
const NodeItem &other,
|
||||||
|
const NodeItem &if_val,
|
||||||
|
const NodeItem &else_val) const
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case CompareOp::Less:
|
||||||
|
return other.if_else(CompareOp::Greater, *this, else_val, if_val);
|
||||||
|
case CompareOp::LessEq:
|
||||||
|
return other.if_else(CompareOp::GreaterEq, *this, else_val, if_val);
|
||||||
|
case CompareOp::NotEq:
|
||||||
|
return if_else(CompareOp::Eq, other, else_val, if_val);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem res = empty();
|
||||||
|
if (type() != Type::Float || other.type() != Type::Float) {
|
||||||
BogdanNagirniak marked this conversation as resolved
Georgiy Markelov
commented
Should Should `Integer` be here?
Bogdan Nagirniak
commented
Discussed: let it be here Discussed: let it be here
|
|||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item1 = if_val;
|
||||||
|
auto item2 = else_val;
|
||||||
|
Type to_type = adjust_types(item1, item2);
|
||||||
|
if (to_type == Type::Empty) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<bool(float, float)> func = nullptr;
|
||||||
|
std::string mx_category;
|
||||||
|
switch (op) {
|
||||||
|
case CompareOp::Greater:
|
||||||
|
mx_category = "ifgreater";
|
||||||
|
func = [](float a, float b) { return a > b; };
|
||||||
|
break;
|
||||||
|
case CompareOp::GreaterEq:
|
||||||
|
mx_category = "ifgreatereq";
|
||||||
|
func = [](float a, float b) { return a >= b; };
|
||||||
|
break;
|
||||||
|
case CompareOp::Eq:
|
||||||
|
mx_category = "ifequal";
|
||||||
|
func = [](float a, float b) { return a == b; };
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && other.value) {
|
||||||
|
res = func(value->asA<float>(), other.value->asA<float>()) ? item1 : item2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(to_type));
|
||||||
|
res.set_input("value1", *this);
|
||||||
|
res.set_input("value2", other);
|
||||||
|
res.set_input("in1", item1);
|
||||||
|
res.set_input("in2", item2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::empty() const
|
||||||
|
{
|
||||||
|
return NodeItem(graph_);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem::Type NodeItem::type() const
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
return type(value->getTypeString());
|
||||||
|
}
|
||||||
|
if (node) {
|
||||||
|
return type(node->getType());
|
||||||
|
}
|
||||||
|
return Type::Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeItem::set_input(const std::string &name,
|
||||||
|
const NodeItem &item,
|
||||||
|
const std::string &output_name)
|
||||||
|
{
|
||||||
|
if (item.value) {
|
||||||
|
Type item_type = item.type();
|
||||||
|
std::string mx_type = type(item_type);
|
||||||
|
switch (item_type) {
|
||||||
|
case Type::String:
|
||||||
|
set_input(name, item.value->asA<std::string>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Integer:
|
||||||
|
set_input(name, item.value->asA<int>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Float:
|
||||||
|
set_input(name, item.value->asA<float>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Vector2:
|
||||||
|
set_input(name, item.value->asA<MaterialX::Vector2>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Vector3:
|
||||||
|
set_input(name, item.value->asA<MaterialX::Vector3>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Vector4:
|
||||||
|
set_input(name, item.value->asA<MaterialX::Vector4>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Color3:
|
||||||
|
set_input(name, item.value->asA<MaterialX::Color3>(), mx_type);
|
||||||
|
break;
|
||||||
|
case Type::Color4:
|
||||||
|
set_input(name, item.value->asA<MaterialX::Color4>(), mx_type);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item.node) {
|
||||||
|
node->setConnectedNode(name, item.node);
|
||||||
|
if (output_name != "") {
|
||||||
|
node->setConnectedOutput(name, item.node->getOutput(output_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeItem::set_input(const std::string &name,
|
||||||
|
const NodeItem &item,
|
||||||
|
Type in_type,
|
||||||
|
const std::string &output_name)
|
||||||
|
{
|
||||||
|
set_input(name, item.convert(in_type), output_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeItem::add_output(const std::string &name, Type out_type)
|
||||||
|
{
|
||||||
|
node->addOutput(name, type(out_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem::Type NodeItem::type(const std::string &type_str)
|
||||||
|
{
|
||||||
|
if (type_str == "string") {
|
||||||
|
return Type::String;
|
||||||
|
}
|
||||||
|
if (type_str == "integer") {
|
||||||
|
return Type::Integer;
|
||||||
|
}
|
||||||
|
if (type_str == "float") {
|
||||||
|
return Type::Float;
|
||||||
|
}
|
||||||
|
if (type_str == "vector2") {
|
||||||
|
return Type::Vector2;
|
||||||
|
}
|
||||||
|
if (type_str == "vector3") {
|
||||||
|
return Type::Vector3;
|
||||||
|
}
|
||||||
|
if (type_str == "vector4") {
|
||||||
|
return Type::Vector4;
|
||||||
|
}
|
||||||
|
if (type_str == "color3") {
|
||||||
|
return Type::Color3;
|
||||||
|
}
|
||||||
|
if (type_str == "color4") {
|
||||||
|
return Type::Color4;
|
||||||
|
}
|
||||||
|
return Type::Other;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NodeItem::type(Type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case Type::String:
|
||||||
|
return "string";
|
||||||
|
case Type::Integer:
|
||||||
|
return "integer";
|
||||||
|
case Type::Float:
|
||||||
|
return "float";
|
||||||
|
case Type::Vector2:
|
||||||
|
return "vector2";
|
||||||
|
case Type::Vector3:
|
||||||
|
return "vector3";
|
||||||
|
case Type::Vector4:
|
||||||
|
return "vector4";
|
||||||
|
case Type::Color3:
|
||||||
|
return "color3";
|
||||||
|
case Type::Color4:
|
||||||
|
return "color4";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeItem::is_arithmetic(Type type)
|
||||||
|
{
|
||||||
|
return type >= Type::Float;
|
||||||
BogdanNagirniak marked this conversation as resolved
Outdated
Georgiy Markelov
commented
Type::Float -> Type::Integer Type::Float -> Type::Integer
Bogdan Nagirniak
commented
Integer isn't used in arithmetic operations Integer isn't used in arithmetic operations
|
|||||||
|
}
|
||||||
|
|
||||||
|
NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
|
||||||
|
{
|
||||||
|
Type t1 = item1.type();
|
||||||
|
Type t2 = item2.type();
|
||||||
|
if (t1 == t2) {
|
||||||
|
return t1;
|
||||||
|
}
|
||||||
|
if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
|
||||||
|
return Type::Empty;
|
||||||
|
}
|
||||||
|
if (t1 < t2) {
|
||||||
|
item1 = item1.convert(t2);
|
||||||
|
return t2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item2 = item2.convert(t1);
|
||||||
|
return t1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeItem::is_arithmetic() const
|
||||||
|
{
|
||||||
|
return is_arithmetic(type());
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(float)> func) const
|
||||||
|
{
|
||||||
|
NodeItem res = empty();
|
||||||
|
Type type = this->type();
|
||||||
|
if (!is_arithmetic(type)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
switch (type) {
|
||||||
|
case Type::Float: {
|
||||||
|
float v = value->asA<float>();
|
||||||
|
res.value = MaterialX::Value::createValue<float>(func(v));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Color3: {
|
||||||
|
auto v = value->asA<MaterialX::Color3>();
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
||||||
|
{func(v[0]), func(v[1]), func(v[2])});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::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])});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Vector2: {
|
||||||
|
auto v = value->asA<MaterialX::Vector2>();
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
|
||||||
|
}
|
||||||
|
case Type::Vector3: {
|
||||||
|
auto v = value->asA<MaterialX::Vector3>();
|
||||||
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
||||||
|
{func(v[0]), func(v[1]), func(v[2])});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::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])});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* TODO: Some of math functions (sin, cos, ...) doesn't work with Color types,
|
||||||
|
* we have to convert to Vector */
|
||||||
|
res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, this->type(type));
|
||||||
res.set_input("in", *this);
|
res.set_input("in", *this);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::arithmetic(const NodeItem &other,
|
NodeItem NodeItem::arithmetic(const NodeItem &other,
|
||||||
const std::string &mx_category,
|
const std::string &category,
|
||||||
std::function<float(float, float)> func) const
|
std::function<float(float, float)> func) const
|
||||||
{
|
{
|
||||||
NodeItem res = empty();
|
NodeItem res = empty();
|
||||||
if (!is_numeric() || !other.is_numeric()) {
|
NodeItem item1 = *this;
|
||||||
|
NodeItem item2 = other;
|
||||||
|
Type to_type = adjust_types(item1, item2);
|
||||||
|
if (to_type == Type::Empty) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mx_type;
|
|
||||||
if (value && other.value) {
|
if (value && other.value) {
|
||||||
auto val1 = value;
|
switch (to_type) {
|
||||||
auto val2 = other.value;
|
case Type::Float: {
|
||||||
if (!adjust_types(val1, val2, mx_type)) {
|
float v1 = item1.value->asA<float>();
|
||||||
return res;
|
float v2 = item2.value->asA<float>();
|
||||||
}
|
|
||||||
|
|
||||||
if (mx_type == "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));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "color3") {
|
case Type::Color3: {
|
||||||
auto v1 = val1->asA<MaterialX::Color3>();
|
auto v1 = item1.value->asA<MaterialX::Color3>();
|
||||||
auto v2 = val2->asA<MaterialX::Color3>();
|
auto v2 = item2.value->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])});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "color4") {
|
case Type::Color4: {
|
||||||
auto v1 = val1->asA<MaterialX::Color4>();
|
auto v1 = item1.value->asA<MaterialX::Color4>();
|
||||||
auto v2 = val2->asA<MaterialX::Color4>();
|
auto v2 = item2.value->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])});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "vector2") {
|
case Type::Vector2: {
|
||||||
auto v1 = val1->asA<MaterialX::Vector2>();
|
auto v1 = item1.value->asA<MaterialX::Vector2>();
|
||||||
auto v2 = val2->asA<MaterialX::Vector2>();
|
auto v2 = item2.value->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])});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "vector3") {
|
case Type::Vector3: {
|
||||||
auto v1 = val1->asA<MaterialX::Vector3>();
|
auto v1 = item1.value->asA<MaterialX::Vector3>();
|
||||||
auto v2 = val2->asA<MaterialX::Vector3>();
|
auto v2 = item2.value->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])});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (mx_type == "vector4") {
|
case Type::Vector4: {
|
||||||
auto v1 = val1->asA<MaterialX::Vector4>();
|
auto v1 = item1.value->asA<MaterialX::Vector4>();
|
||||||
auto v2 = val2->asA<MaterialX::Vector4>();
|
auto v2 = item2.value->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])});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else {
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto val1 = *this;
|
res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type(to_type));
|
||||||
auto val2 = other;
|
res.set_input("in1", item1);
|
||||||
if (!adjust_types(val1, val2, mx_type)) {
|
res.set_input("in2", item2);
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type);
|
|
||||||
res.set_input("in1", val1);
|
|
||||||
res.set_input("in2", val2);
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string mx_type)
|
|
||||||
{
|
|
||||||
if (mx_type == "float") {
|
|
||||||
return MaterialX::Value::createValue<float>(v);
|
|
||||||
}
|
|
||||||
if (mx_type == "color3") {
|
|
||||||
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,
|
|
||||||
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<float>(), t2);
|
|
||||||
mx_type = t2;
|
|
||||||
}
|
|
||||||
else if (t2 == "float") {
|
|
||||||
val2 = float_to_type(val2->asA<float>(), t1);
|
|
||||||
mx_type = t1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mx_type = t1;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<float>(), t2);
|
|
||||||
mx_type = t2;
|
|
||||||
}
|
|
||||||
else if (val2.value && t2 == "float") {
|
|
||||||
val2.value = float_to_type(val2.value->asA<float>(), t1);
|
|
||||||
mx_type = t1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mx_type = t1;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace blender::nodes::materialx
|
} // namespace blender::nodes::materialx
|
||||||
|
@ -9,6 +9,21 @@
|
|||||||
namespace blender::nodes::materialx {
|
namespace blender::nodes::materialx {
|
||||||
|
|
||||||
class NodeItem {
|
class NodeItem {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Empty = 0,
|
||||||
|
Other, /* For MaterialX types like: surfaceshader, bsdf, edf, ...*/
|
||||||
BogdanNagirniak marked this conversation as resolved
Outdated
Georgiy Markelov
commented
Add comment what is Add comment what is `Other`
|
|||||||
|
String,
|
||||||
|
Integer,
|
||||||
|
Float,
|
||||||
|
Vector2,
|
||||||
|
Vector3,
|
||||||
|
Vector4,
|
||||||
|
Color3,
|
||||||
|
Color4
|
||||||
|
};
|
||||||
|
enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq };
|
||||||
BogdanNagirniak marked this conversation as resolved
Outdated
Georgiy Markelov
commented
IfType -> ComparisonType IfType -> ComparisonType
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
MaterialX::ValuePtr value;
|
MaterialX::ValuePtr value;
|
||||||
MaterialX::NodePtr node;
|
MaterialX::NodePtr node;
|
||||||
@ -20,20 +35,7 @@ class NodeItem {
|
|||||||
NodeItem(MaterialX::GraphElement *graph);
|
NodeItem(MaterialX::GraphElement *graph);
|
||||||
~NodeItem() = default;
|
~NodeItem() = default;
|
||||||
|
|
||||||
NodeItem empty() const;
|
/* Operators */
|
||||||
BogdanNagirniak marked this conversation as resolved
Georgiy Markelov
commented
Suggest add Suggest add `#pragma region` for such places
Bogdan Nagirniak
commented
It is not commonly used in Blender code It is not commonly used in Blender code
|
|||||||
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,
|
|
||||||
const std::string &output_name = "");
|
|
||||||
void set_input(const std::string &name, const MaterialX::ValuePtr value);
|
|
||||||
void set_input(const std::string &name,
|
|
||||||
const MaterialX::NodePtr node,
|
|
||||||
const std::string &output_name = "");
|
|
||||||
void add_output(const std::string &name, const std::string &mx_type);
|
|
||||||
|
|
||||||
operator bool() const;
|
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;
|
||||||
@ -45,16 +47,13 @@ class NodeItem {
|
|||||||
bool operator==(const NodeItem &other) const;
|
bool operator==(const NodeItem &other) const;
|
||||||
bool operator!=(const NodeItem &other) const;
|
bool operator!=(const NodeItem &other) const;
|
||||||
|
|
||||||
|
/* Math functions */
|
||||||
NodeItem abs() const;
|
NodeItem abs() const;
|
||||||
NodeItem floor() const;
|
NodeItem floor() const;
|
||||||
NodeItem ceil() const;
|
NodeItem ceil() const;
|
||||||
NodeItem min(const NodeItem &other) const;
|
NodeItem min(const NodeItem &other) const;
|
||||||
NodeItem max(const NodeItem &other) const;
|
NodeItem max(const NodeItem &other) const;
|
||||||
NodeItem dotproduct(const NodeItem &other) const;
|
NodeItem dotproduct(const NodeItem &other) const;
|
||||||
NodeItem if_else(const std::string &condition,
|
|
||||||
const NodeItem &other,
|
|
||||||
const NodeItem &if_val,
|
|
||||||
const NodeItem &else_val) const;
|
|
||||||
NodeItem blend(const NodeItem &a, const NodeItem &b) const;
|
NodeItem blend(const NodeItem &a, const NodeItem &b) const;
|
||||||
NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) 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 clamp(float min_val = 0.0f, float max_val = 1.0f) const;
|
||||||
@ -72,22 +71,40 @@ class NodeItem {
|
|||||||
NodeItem sqrt() const;
|
NodeItem sqrt() const;
|
||||||
NodeItem sign() const;
|
NodeItem sign() const;
|
||||||
NodeItem exp() const;
|
NodeItem exp() const;
|
||||||
|
NodeItem convert(Type to_type) const;
|
||||||
|
NodeItem if_else(CompareOp op,
|
||||||
|
const NodeItem &other,
|
||||||
|
const NodeItem &if_val,
|
||||||
|
const NodeItem &else_val) const;
|
||||||
|
|
||||||
NodeItem to_color3() const;
|
/* Useful functions */
|
||||||
bool is_numeric() const;
|
NodeItem empty() const;
|
||||||
std::string type() const;
|
template<class T> NodeItem val(const T &data) const;
|
||||||
|
Type type() const;
|
||||||
|
|
||||||
|
/* Functions to set input and output */
|
||||||
|
template<class T>
|
||||||
|
void set_input(const std::string &in_name, const T &value, const std::string &in_type);
|
||||||
|
void set_input(const std::string &in_name,
|
||||||
|
const NodeItem &item,
|
||||||
|
const std::string &out_name = "");
|
||||||
|
void set_input(const std::string &in_name,
|
||||||
|
const NodeItem &item,
|
||||||
|
Type in_type,
|
||||||
|
const std::string &out_name = "");
|
||||||
|
void add_output(const std::string &in_name, Type out_type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeItem arithmetic(const std::string &mx_category, std::function<float(float)> func) const;
|
static Type type(const std::string &type_str);
|
||||||
|
static std::string type(Type type);
|
||||||
|
static bool is_arithmetic(Type type);
|
||||||
|
static Type adjust_types(NodeItem &item1, NodeItem &item2);
|
||||||
|
|
||||||
|
bool is_arithmetic() const;
|
||||||
|
NodeItem arithmetic(const std::string &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 &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);
|
|
||||||
/* 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<class T> NodeItem NodeItem::val(const T &data) const
|
template<class T> NodeItem NodeItem::val(const T &data) const
|
||||||
@ -98,9 +115,9 @@ template<class T> NodeItem NodeItem::val(const T &data) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 &in_name, const T &value, const std::string &in_type)
|
||||||
{
|
{
|
||||||
node->setInputValue(name, value, mx_type);
|
node->setInputValue(in_name, value, in_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blender::nodes::materialx
|
} // namespace blender::nodes::materialx
|
||||||
|
@ -14,7 +14,11 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph,
|
|||||||
const Material *material,
|
const Material *material,
|
||||||
const bNode *node,
|
const bNode *node,
|
||||||
const bNodeSocket *socket_out)
|
const bNodeSocket *socket_out)
|
||||||
: graph_(graph), depsgraph_(depsgraph), material_(material), node_(node), socket_out_(socket_out)
|
: graph_(graph),
|
||||||
|
depsgraph_(depsgraph),
|
||||||
|
material_(material),
|
||||||
|
node_(node),
|
||||||
|
socket_out_(socket_out)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,17 +78,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);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,8 @@ NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name)
|
|||||||
NodeItem OutputMaterialNodeParser::compute_default()
|
NodeItem OutputMaterialNodeParser::compute_default()
|
||||||
{
|
{
|
||||||
NodeItem surface = create_node("standard_surface", "surfaceshader");
|
NodeItem surface = create_node("standard_surface", "surfaceshader");
|
||||||
surface.set_input("base_color", value(MaterialX::Color3(material_->r, material_->g, material_->b)));
|
surface.set_input("base_color",
|
||||||
|
value(MaterialX::Color3(material_->r, material_->g, material_->b)));
|
||||||
surface.set_input("diffuse_roughness", value(material_->roughness));
|
surface.set_input("diffuse_roughness", value(material_->roughness));
|
||||||
if (material_->metallic > 0.0f) {
|
if (material_->metallic > 0.0f) {
|
||||||
surface.set_input("metalness", value(material_->metallic));
|
surface.set_input("metalness", value(material_->metallic));
|
||||||
|
@ -8,23 +8,20 @@ namespace blender::nodes::materialx {
|
|||||||
|
|
||||||
NodeItem TexCheckerNodeParser::compute()
|
NodeItem TexCheckerNodeParser::compute()
|
||||||
{
|
{
|
||||||
NodeItem scale = get_input_value("Scale");
|
NodeItem vector = get_input_link("Vector");
|
||||||
NodeItem color1 = get_input_value("Color1");
|
NodeItem color1 = get_input_value("Color1");
|
||||||
NodeItem color2 = get_input_value("Color2");
|
NodeItem color2 = get_input_value("Color2");
|
||||||
|
NodeItem scale = get_input_value("Scale");
|
||||||
|
|
||||||
if (scale.value && scale.type() == "float") {
|
if (!vector) {
|
||||||
float v = scale.value->asA<float>();
|
vector = create_node("texcoord", "vector2");
|
||||||
scale = value(MaterialX::Vector2(v, v));
|
|
||||||
}
|
}
|
||||||
|
vector = vector * scale;
|
||||||
NodeItem texcoord = create_node("texcoord", "vector2");
|
|
||||||
NodeItem place2d = create_node("place2d", "vector2");
|
|
||||||
place2d.set_input("texcoord", texcoord * scale);
|
|
||||||
|
|
||||||
NodeItem separate = create_node("separate2", "multioutput");
|
NodeItem separate = create_node("separate2", "multioutput");
|
||||||
separate.set_input("in", place2d);
|
separate.set_input("in", vector, NodeItem::Type::Vector2);
|
||||||
separate.add_output("outx", "float");
|
separate.add_output("outx", NodeItem::Type::Float);
|
||||||
separate.add_output("outy", "float");
|
separate.add_output("outy", NodeItem::Type::Float);
|
||||||
|
|
||||||
NodeItem modulo_x = create_node("modulo", "float");
|
NodeItem modulo_x = create_node("modulo", "float");
|
||||||
modulo_x.set_input("in1", separate, "outx");
|
modulo_x.set_input("in1", separate, "outx");
|
||||||
@ -34,12 +31,12 @@ NodeItem TexCheckerNodeParser::compute()
|
|||||||
modulo_y.set_input("in1", separate, "outy");
|
modulo_y.set_input("in1", separate, "outy");
|
||||||
modulo_y.set_input("in2", value(2.0f));
|
modulo_y.set_input("in2", value(2.0f));
|
||||||
|
|
||||||
NodeItem ifequal =
|
NodeItem ifequal = (modulo_x.floor() + modulo_y.floor())
|
||||||
(modulo_x.floor() + modulo_y.floor()).if_else("==", value(1.0f), value(0.0f), value(1.0f));
|
.if_else(NodeItem::CompareOp::Eq, value(1.0f), value(0.0f), value(1.0f));
|
||||||
|
|
||||||
NodeItem res = create_node("mix", "color3");
|
NodeItem res = create_node("mix", "color3");
|
||||||
res.set_input("bg", color1.to_color3());
|
res.set_input("bg", color1, NodeItem::Type::Color3);
|
||||||
res.set_input("fg", color2.to_color3());
|
res.set_input("fg", color2, NodeItem::Type::Color3);
|
||||||
res.set_input("mix", ifequal);
|
res.set_input("mix", ifequal);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,15 @@ 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>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem texcoord = create_node("position", "vector3");
|
NodeItem position = create_node("position", "vector3");
|
||||||
|
position = position * scale;
|
||||||
|
|
||||||
NodeItem res = create_node("fractal3d", "color3");
|
NodeItem res = create_node("fractal3d", "color3");
|
||||||
res.set_input("position", texcoord * scale);
|
res.set_input("position", position, NodeItem::Type::Vector3);
|
||||||
res.set_input("octaves", detail);
|
res.set_input("octaves", detail);
|
||||||
res.set_input("lacunarity", lacunarity);
|
res.set_input("lacunarity", lacunarity);
|
||||||
return res;
|
return res;
|
||||||
|
Loading…
Reference in New Issue
Block a user
tp -> from_type