forked from blender/blender
Code improvements + Mix node #30
@ -83,7 +83,7 @@ void MaterialData::init()
|
|||||||
scene_delegate_->depsgraph, (Material *)id, cache_or_get_image_file);
|
scene_delegate_->depsgraph, (Material *)id, cache_or_get_image_file);
|
||||||
pxr::UsdMtlxRead(doc, stage);
|
pxr::UsdMtlxRead(doc, stage);
|
||||||
|
|
||||||
/* Logging stage: creating lambda stage_str() for not to call stage->ExportToString()
|
/* Logging stage: creating lambda stage_str() to not call stage->ExportToString()
|
||||||
* if log won't be printed. */
|
* if log won't be printed. */
|
||||||
auto stage_str = [&stage]() {
|
auto stage_str = [&stage]() {
|
||||||
std::string str;
|
std::string str;
|
||||||
|
@ -182,6 +182,38 @@ NodeItem NodeItem::operator^(const NodeItem &other) const
|
|||||||
return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); });
|
return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::operator[](int index) const
|
||||||
|
{
|
||||||
|
BLI_assert(is_arithmetic(type()));
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
float v = 0.0f;
|
||||||
|
switch (type()) {
|
||||||
|
case Type::Float:
|
||||||
|
v = value->asA<float>();
|
||||||
|
break;
|
||||||
|
case Type::Vector2:
|
||||||
|
v = value->asA<MaterialX::Vector2>()[index];
|
||||||
|
case Type::Vector3:
|
||||||
|
v = value->asA<MaterialX::Vector3>()[index];
|
||||||
|
break;
|
||||||
|
case Type::Vector4:
|
||||||
|
v = value->asA<MaterialX::Vector4>()[index];
|
||||||
|
break;
|
||||||
|
case Type::Color3:
|
||||||
|
v = value->asA<MaterialX::Color3>()[index];
|
||||||
|
break;
|
||||||
|
case Type::Color4:
|
||||||
|
v = value->asA<MaterialX::Color4>()[index];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
return val(v);
|
||||||
|
}
|
||||||
|
return create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}});
|
||||||
|
}
|
||||||
|
|
||||||
bool NodeItem::operator==(const NodeItem &other) const
|
bool NodeItem::operator==(const NodeItem &other) const
|
||||||
{
|
{
|
||||||
if (!*this) {
|
if (!*this) {
|
||||||
@ -226,6 +258,22 @@ NodeItem NodeItem::ceil() const
|
|||||||
return arithmetic("ceil", [](float a) { return std::ceilf(a); });
|
return arithmetic("ceil", [](float a) { return std::ceilf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::length() const
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
return dotproduct(*this).sqrt();
|
||||||
|
}
|
||||||
|
return create_node("magnitude", Type::Float, {{"in", to_vector()}});
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::normalize() const
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
return *this / length();
|
||||||
|
}
|
||||||
|
return create_node("normalize", Type::Vector3, {{"in", to_vector()}});
|
||||||
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::min(const NodeItem &other) const
|
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); });
|
||||||
@ -238,56 +286,86 @@ NodeItem NodeItem::max(const NodeItem &other) const
|
|||||||
|
|
||||||
NodeItem NodeItem::dotproduct(const NodeItem &other) const
|
NodeItem NodeItem::dotproduct(const NodeItem &other) const
|
||||||
{
|
{
|
||||||
NodeItem d = arithmetic(
|
if (value && other.value) {
|
||||||
other, "dotproduct", [](float a, float b) { return a * b; }, Type::Float);
|
NodeItem d = *this * other;
|
||||||
BogdanNagirniak marked this conversation as resolved
|
|||||||
if (d.value) {
|
|
||||||
float f = 0.0f;
|
float f = 0.0f;
|
||||||
switch (d.type()) {
|
switch (d.type()) {
|
||||||
case Type::Float: {
|
case Type::Float: {
|
||||||
f = value->asA<float>();
|
f = d.value->asA<float>();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Vector2: {
|
case Type::Vector2: {
|
||||||
auto v = value->asA<MaterialX::Vector2>();
|
auto v = d.value->asA<MaterialX::Vector2>();
|
||||||
f = v[0] + v[1];
|
f = v[0] + v[1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Vector3: {
|
case Type::Vector3: {
|
||||||
auto v = value->asA<MaterialX::Vector3>();
|
auto v = d.value->asA<MaterialX::Vector3>();
|
||||||
f = v[0] + v[1] + v[2];
|
f = v[0] + v[1] + v[2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Vector4: {
|
case Type::Vector4: {
|
||||||
auto v = value->asA<MaterialX::Vector4>();
|
auto v = d.value->asA<MaterialX::Vector4>();
|
||||||
f = v[0] + v[1] + v[2] + v[3];
|
f = v[0] + v[1] + v[2] + v[3];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Color3: {
|
case Type::Color3: {
|
||||||
auto v = value->asA<MaterialX::Color3>();
|
auto v = d.value->asA<MaterialX::Color3>();
|
||||||
f = v[0] + v[1] + v[2];
|
f = v[0] + v[1] + v[2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Color4: {
|
case Type::Color4: {
|
||||||
auto v = value->asA<MaterialX::Color4>();
|
auto v = d.value->asA<MaterialX::Color4>();
|
||||||
f = v[0] + v[1] + v[2] + v[3];
|
f = v[0] + v[1] + v[2] + v[3];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
d.value = MaterialX::Value::createValue(f);
|
return val(f);
|
||||||
}
|
}
|
||||||
return d;
|
|
||||||
|
NodeItem item1 = to_vector();
|
||||||
|
NodeItem item2 = other.to_vector();
|
||||||
|
cast_types(item1, item2);
|
||||||
|
return create_node("dotproduct", Type::Float, {{"in1", item1}, {"in2", item2}});
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
|
NodeItem NodeItem::mix(const NodeItem &val1, const NodeItem &val2) const
|
||||||
{
|
{
|
||||||
return (val(1.0f) - *this) * a + *this * b;
|
if ((value && val1.value && val2.value) || type() != Type::Float) {
|
||||||
|
return (val(1.0f) - *this) * val1 + *this * val2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type1 = val1.type();
|
||||||
|
if (ELEM(type1, Type::BSDF, Type::EDF)) {
|
||||||
|
BLI_assert(val2.type() == type1);
|
||||||
|
|
||||||
|
/* Special case: mix BSDF/EDF shaders */
|
||||||
|
return create_node("mix", type1, {{"bg", val1}, {"fg", val2}, {"mix", *this}});
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeItem item1 = val1;
|
||||||
|
NodeItem item2 = val2;
|
||||||
|
Type to_type = cast_types(item1, item2);
|
||||||
|
return create_node("mix", to_type, {{"bg", item1}, {"fg", item2}, {"mix", *this}});
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const
|
NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const
|
||||||
{
|
{
|
||||||
return min(max_val).max(min_val);
|
if (value && min_val.value && max_val.value) {
|
||||||
|
return min(max_val).max(min_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_val.type() == Type::Float && max_val.type() == Type::Float) {
|
||||||
|
return create_node("clamp", type(), {{"in", *this}, {"low", min_val}, {"high", max_val}});
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = this->type();
|
||||||
|
return create_node(
|
||||||
|
"clamp",
|
||||||
|
type,
|
||||||
|
{{"in", *this}, {"low", min_val.convert(type)}, {"high", max_val.convert(type)}});
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::clamp(float min_val, float max_val) const
|
NodeItem NodeItem::clamp(float min_val, float max_val) const
|
||||||
@ -295,64 +373,95 @@ NodeItem NodeItem::clamp(float min_val, float max_val) const
|
|||||||
return clamp(val(min_val), val(max_val));
|
return clamp(val(min_val), val(max_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::rotate(const NodeItem &angle, const NodeItem &axis)
|
||||||
|
{
|
||||||
|
BLI_assert(type() == Type::Vector3);
|
||||||
|
BLI_assert(angle.type() == Type::Float);
|
||||||
|
BLI_assert(axis.type() == Type::Vector3);
|
||||||
|
|
||||||
|
return create_node(
|
||||||
|
"rotate3d", NodeItem::Type::Vector3, {{"in", *this}, {"amount", angle}, {"axis", axis}});
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::rotate(const NodeItem &angle_xyz, bool invert)
|
||||||
|
{
|
||||||
|
NodeItem x = angle_xyz[0];
|
||||||
|
NodeItem y = angle_xyz[1];
|
||||||
|
NodeItem z = angle_xyz[2];
|
||||||
|
if (invert) {
|
||||||
|
return rotate(z, val(MaterialX::Vector3(0.0f, 0.0f, 1.0f)))
|
||||||
|
.rotate(y, val(MaterialX::Vector3(0.0f, 1.0f, 0.0f)))
|
||||||
|
.rotate(x, val(MaterialX::Vector3(1.0f, 0.0f, 0.0f)));
|
||||||
|
}
|
||||||
|
return rotate(x, val(MaterialX::Vector3(1.0f, 0.0f, 0.0f)))
|
||||||
|
.rotate(y, val(MaterialX::Vector3(0.0f, 1.0f, 0.0f)))
|
||||||
|
.rotate(z, val(MaterialX::Vector3(0.0f, 0.0f, 1.0f)));
|
||||||
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::sin() const
|
NodeItem NodeItem::sin() const
|
||||||
{
|
{
|
||||||
return arithmetic("sin", [](float a) { return std::sinf(a); });
|
return to_vector().arithmetic("sin", [](float a) { return std::sinf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::cos() const
|
NodeItem NodeItem::cos() const
|
||||||
{
|
{
|
||||||
return arithmetic("cos", [](float a) { return std::cosf(a); });
|
return to_vector().arithmetic("cos", [](float a) { return std::cosf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::tan() const
|
NodeItem NodeItem::tan() const
|
||||||
{
|
{
|
||||||
return arithmetic("tan", [](float a) { return std::tanf(a); });
|
return to_vector().arithmetic("tan", [](float a) { return std::tanf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::asin() const
|
NodeItem NodeItem::asin() const
|
||||||
{
|
{
|
||||||
return arithmetic("asin", [](float a) { return std::asinf(a); });
|
return to_vector().arithmetic("asin", [](float a) { return std::asinf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::acos() const
|
NodeItem NodeItem::acos() const
|
||||||
{
|
{
|
||||||
return arithmetic("acos", [](float a) { return std::acosf(a); });
|
return to_vector().arithmetic("acos", [](float a) { return std::acosf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::atan() const
|
NodeItem NodeItem::atan() const
|
||||||
{
|
{
|
||||||
return arithmetic("atan", [](float a) { return std::atanf(a); });
|
return to_vector().arithmetic("atan", [](float a) { return std::atanf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::atan2(const NodeItem &other) const
|
NodeItem NodeItem::atan2(const NodeItem &other) const
|
||||||
{
|
{
|
||||||
return arithmetic(other, "atan2", [](float a, float b) { return std::atan2f(a, b); });
|
return to_vector().arithmetic(
|
||||||
|
other, "atan2", [](float a, float b) { return std::atan2f(a, b); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::sinh() const
|
NodeItem NodeItem::sinh() const
|
||||||
{
|
{
|
||||||
return (exp() - (-*this).exp()) / val(2.0f);
|
NodeItem v = to_vector();
|
||||||
|
return (v.exp() - (-v).exp()) / val(2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::cosh() const
|
NodeItem NodeItem::cosh() const
|
||||||
{
|
{
|
||||||
return (exp() - (-*this).exp()) / val(2.0f);
|
NodeItem v = to_vector();
|
||||||
|
return (v.exp() + (-v).exp()) / val(2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::tanh() const
|
NodeItem NodeItem::tanh() const
|
||||||
{
|
{
|
||||||
return sinh() / cosh();
|
NodeItem v = to_vector();
|
||||||
|
NodeItem a = v.exp();
|
||||||
|
NodeItem b = (-v).exp();
|
||||||
|
return (a - b) / (a + b);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::ln() const
|
NodeItem NodeItem::ln() const
|
||||||
{
|
{
|
||||||
return arithmetic("ln", [](float a) { return std::logf(a); });
|
return to_vector().arithmetic("ln", [](float a) { return std::logf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::sqrt() const
|
NodeItem NodeItem::sqrt() const
|
||||||
{
|
{
|
||||||
return arithmetic("sqrt", [](float a) { return std::sqrtf(a); });
|
return to_vector().arithmetic("sqrt", [](float a) { return std::sqrtf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::sign() const
|
NodeItem NodeItem::sign() const
|
||||||
@ -362,7 +471,7 @@ NodeItem NodeItem::sign() const
|
|||||||
|
|
||||||
NodeItem NodeItem::exp() const
|
NodeItem NodeItem::exp() const
|
||||||
{
|
{
|
||||||
return arithmetic("exp", [](float a) { return std::expf(a); });
|
return to_vector().arithmetic("exp", [](float a) { return std::expf(a); });
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::convert(Type to_type) const
|
NodeItem NodeItem::convert(Type to_type) const
|
||||||
@ -380,7 +489,7 @@ NodeItem NodeItem::convert(Type to_type) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (to_type == Type::Float) {
|
if (to_type == Type::Float) {
|
||||||
return extract(0);
|
return (*this)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converting types which requires > 1 iteration */
|
/* Converting types which requires > 1 iteration */
|
||||||
@ -548,6 +657,27 @@ NodeItem NodeItem::convert(Type to_type) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeItem NodeItem::to_vector() const
|
||||||
|
{
|
||||||
|
switch (type()) {
|
||||||
|
case Type::Float:
|
||||||
|
case Type::Vector2:
|
||||||
|
case Type::Vector3:
|
||||||
|
case Type::Vector4:
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
case Type::Color3:
|
||||||
|
return convert(Type::Vector3);
|
||||||
|
|
||||||
|
case Type::Color4:
|
||||||
|
return convert(Type::Vector4);
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::if_else(CompareOp op,
|
NodeItem NodeItem::if_else(CompareOp op,
|
||||||
const NodeItem &other,
|
const NodeItem &other,
|
||||||
const NodeItem &if_val,
|
const NodeItem &if_val,
|
||||||
@ -606,35 +736,11 @@ NodeItem NodeItem::if_else(CompareOp op,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::extract(const int index) const
|
|
||||||
{
|
|
||||||
/* TODO: Add check if (value) { ... } */
|
|
||||||
NodeItem res = create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem NodeItem::empty() const
|
NodeItem NodeItem::empty() const
|
||||||
{
|
{
|
||||||
return NodeItem(graph_);
|
return NodeItem(graph_);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeItem::rotate3d(NodeItem rotation, bool invert)
|
|
||||||
{
|
|
||||||
NodeItem res = *this;
|
|
||||||
if (res.type() == Type::Vector3 && rotation.type() == Type::Vector3) {
|
|
||||||
for (int i = 0; i <= 2; i++) {
|
|
||||||
int j = invert ? 2 - i : i;
|
|
||||||
MaterialX::Vector3 axis_vector = MaterialX::Vector3();
|
|
||||||
axis_vector[j] = 1.0f;
|
|
||||||
res = create_node(
|
|
||||||
"rotate3d",
|
|
||||||
NodeItem::Type::Vector3,
|
|
||||||
{{"in", res}, {"amount", rotation.extract(j)}, {"axis", val(axis_vector)}});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem::Type NodeItem::type() const
|
NodeItem::Type NodeItem::type() const
|
||||||
{
|
{
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -794,9 +900,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(f
|
|||||||
{
|
{
|
||||||
NodeItem res = empty();
|
NodeItem res = empty();
|
||||||
Type type = this->type();
|
Type type = this->type();
|
||||||
if (!is_arithmetic(type)) {
|
BLI_assert(is_arithmetic(type));
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -838,15 +942,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NodeItem v = *this;
|
res = create_node(category, type, {{"in", *this}});
|
||||||
if (ELEM(type, Type::Color3, Type::Color4) &&
|
|
||||||
ELEM(category, "sin", "cos", "tan", "asin", "acos", "atan2", "sqrt", "ln", "exp"))
|
|
||||||
{
|
|
||||||
/* These functions haven't implementation in MaterialX, converting to Vector types */
|
|
||||||
type = type == Type::Color3 ? Type::Vector3 : Type::Vector4;
|
|
||||||
v = v.convert(type);
|
|
||||||
}
|
|
||||||
res = create_node(category, type, {{"in", v}});
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
|
|
||||||
namespace blender::nodes::materialx {
|
namespace blender::nodes::materialx {
|
||||||
|
|
||||||
/* This class serves as abstraction from MateralX API. It implements arithmetic operations,
|
/**
|
||||||
|
* This class serves as abstraction from MateralX API. It implements arithmetic operations,
|
||||||
* convertions between different types, adding new nodes, setting inputs, etc.
|
* convertions between different types, adding new nodes, setting inputs, etc.
|
||||||
* All work should be done via this class instead of using MaterialX API directly. */
|
* All work should be done via this class instead of using MaterialX API directly.
|
||||||
|
*/
|
||||||
class NodeItem {
|
class NodeItem {
|
||||||
public:
|
public:
|
||||||
using Inputs = std::vector<std::pair<std::string, NodeItem>>;
|
using Inputs = std::vector<std::pair<std::string, NodeItem>>;
|
||||||
@ -21,22 +23,22 @@ class NodeItem {
|
|||||||
Any = 0,
|
Any = 0,
|
||||||
Empty,
|
Empty,
|
||||||
Multioutput,
|
Multioutput,
|
||||||
|
|
||||||
/* Value types */
|
/* Value types */
|
||||||
String,
|
String,
|
||||||
Filename,
|
Filename,
|
||||||
Boolean,
|
Boolean,
|
||||||
Integer,
|
Integer,
|
||||||
/* Block of arithmetic types. Ordered by type cast */
|
|
||||||
|
/* Arithmetic types. NOTE: Ordered by type cast */
|
||||||
Float,
|
Float,
|
||||||
Vector2,
|
Vector2,
|
||||||
Vector3,
|
Vector3,
|
||||||
Color3,
|
Color3,
|
||||||
Vector4,
|
Vector4,
|
||||||
Color4,
|
Color4,
|
||||||
/* End of arithmetic types */
|
|
||||||
|
|
||||||
/* Shader types
|
/* Shader types. NOTE: There are only supported types */
|
||||||
* NOTE: There are only supported types */
|
|
||||||
BSDF,
|
BSDF,
|
||||||
EDF,
|
EDF,
|
||||||
Displacementshader,
|
Displacementshader,
|
||||||
@ -74,6 +76,7 @@ class NodeItem {
|
|||||||
NodeItem operator/(const NodeItem &other) const;
|
NodeItem operator/(const NodeItem &other) const;
|
||||||
NodeItem operator%(const NodeItem &other) const;
|
NodeItem operator%(const NodeItem &other) const;
|
||||||
NodeItem operator^(const NodeItem &other) const;
|
NodeItem operator^(const NodeItem &other) const;
|
||||||
|
NodeItem operator[](int index) const;
|
||||||
bool operator==(const NodeItem &other) const;
|
bool operator==(const NodeItem &other) const;
|
||||||
bool operator!=(const NodeItem &other) const;
|
bool operator!=(const NodeItem &other) const;
|
||||||
|
|
||||||
@ -81,12 +84,16 @@ class NodeItem {
|
|||||||
NodeItem abs() const;
|
NodeItem abs() const;
|
||||||
NodeItem floor() const;
|
NodeItem floor() const;
|
||||||
NodeItem ceil() const;
|
NodeItem ceil() const;
|
||||||
|
NodeItem length() const;
|
||||||
|
NodeItem normalize() 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 blend(const NodeItem &a, const NodeItem &b) const;
|
NodeItem mix(const NodeItem &val1, const NodeItem &val2) 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;
|
||||||
|
NodeItem rotate(const NodeItem &angle, const NodeItem &axis); /* angle in degrees */
|
||||||
|
NodeItem rotate(const NodeItem &angle_xyz, bool invert = false); /* angle in degrees */
|
||||||
NodeItem sin() const;
|
NodeItem sin() const;
|
||||||
NodeItem cos() const;
|
NodeItem cos() const;
|
||||||
NodeItem tan() const;
|
NodeItem tan() const;
|
||||||
@ -102,15 +109,14 @@ class NodeItem {
|
|||||||
NodeItem sign() const;
|
NodeItem sign() const;
|
||||||
NodeItem exp() const;
|
NodeItem exp() const;
|
||||||
NodeItem convert(Type to_type) const;
|
NodeItem convert(Type to_type) const;
|
||||||
|
NodeItem to_vector() const;
|
||||||
NodeItem if_else(CompareOp op,
|
NodeItem if_else(CompareOp op,
|
||||||
const NodeItem &other,
|
const NodeItem &other,
|
||||||
const NodeItem &if_val,
|
const NodeItem &if_val,
|
||||||
const NodeItem &else_val) const;
|
const NodeItem &else_val) const;
|
||||||
NodeItem extract(const int index) const;
|
|
||||||
|
|
||||||
/* Useful functions */
|
/* Useful functions */
|
||||||
NodeItem empty() const;
|
NodeItem empty() const;
|
||||||
NodeItem rotate3d(NodeItem rotation, bool invert = false);
|
|
||||||
template<class T> NodeItem val(const T &data) const;
|
template<class T> NodeItem val(const T &data) const;
|
||||||
Type type() const;
|
Type type() const;
|
||||||
|
|
||||||
|
@ -148,13 +148,18 @@ NodeItem NodeParser::empty() const
|
|||||||
return NodeItem(graph_);
|
return NodeItem(graph_);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem NodeParser::texcoord_node()
|
NodeItem NodeParser::texcoord_node(NodeItem::Type type)
|
||||||
{
|
{
|
||||||
|
BLI_assert(ELEM(type, NodeItem::Type::Vector2, NodeItem::Type::Vector3));
|
||||||
|
std::string name = TEXCOORD_NODE_NAME;
|
||||||
|
if (type == NodeItem::Type::Vector3) {
|
||||||
|
name += "_vector3";
|
||||||
|
}
|
||||||
NodeItem res = empty();
|
NodeItem res = empty();
|
||||||
res.node = graph_->getNode(TEXCOORD_NODE_NAME);
|
res.node = graph_->getNode(name);
|
||||||
if (!res.node) {
|
if (!res.node) {
|
||||||
res = create_node("texcoord", NodeItem::Type::Vector2);
|
res = create_node("texcoord", type);
|
||||||
res.node->setName(TEXCOORD_NODE_NAME);
|
res.node->setName(name);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ class GroupNodeParser;
|
|||||||
|
|
||||||
using ExportImageFunction = std::function<std::string(Main *,Scene *, Image *, ImageUser *)>;
|
using ExportImageFunction = std::function<std::string(Main *,Scene *, Image *, ImageUser *)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is base abstraction class for parsing Blender nodes into MaterialX nodes.
|
||||||
|
* NodeParser::compute() should be overrided in child classes.
|
||||||
|
*/
|
||||||
class NodeParser {
|
class NodeParser {
|
||||||
protected:
|
protected:
|
||||||
MaterialX::GraphElement *graph_;
|
MaterialX::GraphElement *graph_;
|
||||||
@ -63,7 +67,7 @@ class NodeParser {
|
|||||||
NodeItem get_input_value(int index, NodeItem::Type to_type);
|
NodeItem get_input_value(int index, NodeItem::Type to_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;
|
||||||
NodeItem texcoord_node();
|
NodeItem texcoord_node(NodeItem::Type type = NodeItem::Type::Vector2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type);
|
NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type);
|
||||||
@ -76,8 +80,21 @@ template<class T> NodeItem NodeParser::val(const T &data) const
|
|||||||
return empty().val(data);
|
return empty().val(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Defines for including MaterialX node parsing code into node_shader_<name>.cc
|
* Defines for including MaterialX node parsing code into node_shader_<name>.cc
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* \code{.c}
|
||||||
|
* NODE_SHADER_MATERIALX_BEGIN
|
||||||
|
* #ifdef WITH_MATERIALX
|
||||||
|
* {
|
||||||
|
* NodeItem color = get_input_value("Color", NodeItem::Type::Color4);
|
||||||
|
* NodeItem gamma = get_input_value("Gamma", NodeItem::Type::Float);
|
||||||
|
* return color ^ gamma;
|
||||||
|
* }
|
||||||
|
* #endif
|
||||||
|
* NODE_SHADER_MATERIALX_END
|
||||||
|
* \endcode
|
||||||
*/
|
*/
|
||||||
struct NodeParserData {
|
struct NodeParserData {
|
||||||
MaterialX::GraphElement *graph;
|
MaterialX::GraphElement *graph;
|
||||||
|
@ -25,36 +25,23 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
|
|||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
NodeItem res = empty();
|
if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) {
|
||||||
switch (to_type_) {
|
return empty();
|
||||||
case NodeItem::Type::BSDF:
|
|
||||||
case NodeItem::Type::EDF: {
|
|
||||||
NodeItem shader1 = get_input_link(0, to_type_);
|
|
||||||
NodeItem shader2 = get_input_link(1, to_type_);
|
|
||||||
|
|
||||||
if (shader1 && !shader2) {
|
|
||||||
res = shader1;
|
|
||||||
}
|
|
||||||
else if (!shader1 && shader2) {
|
|
||||||
res = shader2;
|
|
||||||
}
|
|
||||||
else if (shader1 && shader2) {
|
|
||||||
res = shader1 + shader2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NodeItem::Type::SurfaceShader: {
|
|
||||||
/* SurfaceShaders can't be added, returning the first one connected */
|
|
||||||
res = get_input_link(0, to_type_);
|
|
||||||
if (!res) {
|
|
||||||
res = get_input_link(1, to_type_);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
|
NodeItem shader1 = get_input_link(0, to_type_);
|
||||||
|
NodeItem shader2 = get_input_link(1, to_type_);
|
||||||
|
if (!shader1 && !shader2) {
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shader1 && !shader2) {
|
||||||
|
return shader1;
|
||||||
|
}
|
||||||
|
if (!shader1 && shader2) {
|
||||||
|
return shader2;
|
||||||
|
}
|
||||||
|
return shader1 + shader2;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -289,9 +289,11 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
|
|||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
|
using InputsType = std::map<std::string, NodeItem>;
|
||||||
|
|
||||||
/* NOTE: commented inputs aren't used for node creation. */
|
/* NOTE: commented inputs aren't used for node creation. */
|
||||||
auto bsdf_inputs = [&]() {
|
auto bsdf_inputs = [&]() -> InputsType {
|
||||||
return std::map<std::string, NodeItem>{
|
return {
|
||||||
{"base_color", get_input_value("Base Color", NodeItem::Type::Color3)},
|
{"base_color", get_input_value("Base Color", NodeItem::Type::Color3)},
|
||||||
{"subsurface", get_input_value("Subsurface", NodeItem::Type::Float)},
|
{"subsurface", get_input_value("Subsurface", NodeItem::Type::Float)},
|
||||||
{"subsurface_scale", get_input_value("Subsurface Scale", NodeItem::Type::Float)},
|
{"subsurface_scale", get_input_value("Subsurface Scale", NodeItem::Type::Float)},
|
||||||
@ -320,255 +322,225 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto edf_inputs = [&]() {
|
auto edf_inputs = [&]() -> InputsType {
|
||||||
return std::map<std::string, NodeItem>{
|
return {
|
||||||
{"emission", get_input_value("Emission Strength", NodeItem::Type::Float)},
|
{"emission", get_input_value("Emission Strength", NodeItem::Type::Float)},
|
||||||
{"emission_color", get_input_value("Emission", NodeItem::Type::Color3)}};
|
{"emission_color", get_input_value("Emission", NodeItem::Type::Color3)},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeItem res = empty();
|
NodeItem res = empty();
|
||||||
if (to_type_ == NodeItem::Type::BSDF) {
|
|
||||||
auto in = bsdf_inputs();
|
|
||||||
|
|
||||||
NodeItem roughness = in["roughness"];
|
switch (to_type_) {
|
||||||
NodeItem anisotropy = in["anisotropic"];
|
case NodeItem::Type::BSDF: {
|
||||||
NodeItem rotation = in["anisotropic_rotation"];
|
auto in = bsdf_inputs();
|
||||||
NodeItem base_color = in["base_color"];
|
|
||||||
NodeItem specular = in["specular"];
|
|
||||||
NodeItem coat = in["coat"];
|
|
||||||
NodeItem ior = in["ior"];
|
|
||||||
NodeItem normal = in["normal"];
|
|
||||||
NodeItem tangent = in["tangent"];
|
|
||||||
NodeItem coat_normal = in["coat_normal"];
|
|
||||||
|
|
||||||
NodeItem n_main_tangent = empty();
|
NodeItem roughness = in["roughness"];
|
||||||
if (tangent && normal) {
|
NodeItem anisotropy = in["anisotropic"];
|
||||||
NodeItem n_tangent_rotate = create_node(
|
NodeItem rotation = in["anisotropic_rotation"] * val(360.0f);
|
||||||
"rotate3d",
|
NodeItem base_color = in["base_color"];
|
||||||
NodeItem::Type::Vector3,
|
NodeItem specular = in["specular"];
|
||||||
{{"in", tangent}, {"amount", rotation * val(360.0f)}, {"axis", normal}});
|
NodeItem coat = in["coat"];
|
||||||
|
NodeItem ior = in["ior"];
|
||||||
|
NodeItem normal = in["normal"];
|
||||||
|
NodeItem tangent = in["tangent"];
|
||||||
|
NodeItem coat_normal = in["coat_normal"];
|
||||||
|
|
||||||
NodeItem n_tangent_rotate_normalize = create_node(
|
NodeItem n_main_tangent = empty();
|
||||||
"normalize", NodeItem::Type::Vector3, {{"in", n_tangent_rotate}});
|
if (tangent && normal) {
|
||||||
|
NodeItem n_tangent_rotate_normalize = tangent.rotate(rotation, normal).normalize();
|
||||||
|
n_main_tangent = anisotropy.if_else(
|
||||||
|
NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent);
|
||||||
|
}
|
||||||
|
|
||||||
n_main_tangent = anisotropy.if_else(
|
NodeItem n_coat_roughness_vector = create_node(
|
||||||
NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent);
|
"roughness_anisotropy",
|
||||||
}
|
NodeItem::Type::Vector2,
|
||||||
|
{{"roughness", in["coat_roughness"]}, {"anisotropy", anisotropy}});
|
||||||
|
|
||||||
NodeItem n_coat_roughness_vector = create_node(
|
NodeItem n_coat_bsdf = create_node("dielectric_bsdf",
|
||||||
"roughness_anisotropy",
|
NodeItem::Type::BSDF,
|
||||||
NodeItem::Type::Vector2,
|
{{"weight", coat},
|
||||||
{{"roughness", in["coat_roughness"]}, {"anisotropy", anisotropy}});
|
{"tint", in["coat_tint"]},
|
||||||
|
{"ior", in["coat_ior"]},
|
||||||
|
{"scatter_mode", val(std::string("R"))},
|
||||||
|
{"roughness", n_coat_roughness_vector},
|
||||||
|
{"normal", coat_normal}});
|
||||||
|
|
||||||
NodeItem n_coat_bsdf = create_node("dielectric_bsdf",
|
if (tangent && coat_normal) {
|
||||||
NodeItem::Type::BSDF,
|
NodeItem n_coat_tangent_rotate_normalize =
|
||||||
{{"weight", coat},
|
tangent.rotate(rotation, coat_normal).normalize();
|
||||||
{"tint", in["coat_tint"]},
|
NodeItem n_coat_tangent = anisotropy.if_else(
|
||||||
{"ior", in["coat_ior"]},
|
NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent);
|
||||||
{"scatter_mode", val(std::string("R"))},
|
|
||||||
{"roughness", n_coat_roughness_vector},
|
|
||||||
{"normal", coat_normal}});
|
|
||||||
|
|
||||||
if (tangent && coat_normal) {
|
n_coat_bsdf.set_input("tangent", n_coat_tangent);
|
||||||
NodeItem n_coat_tangent_rotate = create_node(
|
}
|
||||||
"rotate3d",
|
|
||||||
NodeItem::Type::Vector3,
|
|
||||||
{{"in", tangent}, {"amount", rotation * val(360.0f)}, {"axis", coat_normal}});
|
|
||||||
|
|
||||||
NodeItem n_coat_tangent_rotate_normalize = create_node(
|
NodeItem n_thin_film_bsdf = create_node(
|
||||||
"normalize", NodeItem::Type::Vector3, {{"in", n_coat_tangent_rotate}});
|
"thin_film_bsdf", NodeItem::Type::BSDF, {{"thickness", val(0.0f)}, {"ior", val(1.5f)}});
|
||||||
|
|
||||||
NodeItem n_coat_tangent = anisotropy.if_else(
|
NodeItem n_artistic_ior = create_node(
|
||||||
NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent);
|
"artistic_ior",
|
||||||
|
NodeItem::Type::Multioutput,
|
||||||
|
{{"reflectivity", base_color * val(1.0f)}, {"edge_color", base_color * specular}});
|
||||||
|
|
||||||
n_coat_bsdf.set_input("tangent", n_coat_tangent);
|
NodeItem n_ior_out = n_artistic_ior.add_output("ior", NodeItem::Type::Color3);
|
||||||
}
|
NodeItem n_extinction_out = n_artistic_ior.add_output("extinction", NodeItem::Type::Color3);
|
||||||
|
|
||||||
NodeItem n_thin_film_bsdf = create_node(
|
NodeItem n_coat_affect_roughness_multiply2 = coat * val(0.0f) * in["coat_roughness"];
|
||||||
"thin_film_bsdf", NodeItem::Type::BSDF, {{"thickness", val(0.0f)}, {"ior", val(1.5f)}});
|
NodeItem n_coat_affected_roughness = n_coat_affect_roughness_multiply2.mix(roughness,
|
||||||
|
val(1.0f));
|
||||||
|
|
||||||
NodeItem n_artistic_ior = create_node(
|
NodeItem n_main_roughness = create_node(
|
||||||
"artistic_ior",
|
"roughness_anisotropy",
|
||||||
NodeItem::Type::Multioutput,
|
NodeItem::Type::Vector2,
|
||||||
{{"reflectivity", base_color * val(1.0f)}, {"edge_color", base_color * specular}});
|
{{"roughness", n_coat_affected_roughness}, {"anisotropy", anisotropy}});
|
||||||
|
|
||||||
NodeItem n_ior_out = n_artistic_ior.add_output("ior", NodeItem::Type::Color3);
|
NodeItem n_metal_bsdf = create_node("conductor_bsdf",
|
||||||
NodeItem n_extinction_out = n_artistic_ior.add_output("extinction", NodeItem::Type::Color3);
|
|
||||||
|
|
||||||
NodeItem n_coat_affect_roughness_multiply2 = coat * val(0.0f) * in["coat_roughness"];
|
|
||||||
NodeItem n_coat_affected_roughness = create_node(
|
|
||||||
"mix",
|
|
||||||
NodeItem::Type::Float,
|
|
||||||
{{"fg", val(1.0f)}, {"bg", roughness}, {"mix", n_coat_affect_roughness_multiply2}});
|
|
||||||
|
|
||||||
NodeItem n_main_roughness = create_node(
|
|
||||||
"roughness_anisotropy",
|
|
||||||
NodeItem::Type::Vector2,
|
|
||||||
{{"roughness", n_coat_affected_roughness}, {"anisotropy", anisotropy}});
|
|
||||||
|
|
||||||
NodeItem n_metal_bsdf = create_node("conductor_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"ior", n_ior_out},
|
|
||||||
{"extinction", n_extinction_out},
|
|
||||||
{"roughness", n_main_roughness},
|
|
||||||
{"normal", normal},
|
|
||||||
{"tangent", n_main_tangent}});
|
|
||||||
|
|
||||||
NodeItem n_specular_bsdf = create_node("dielectric_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"weight", specular},
|
|
||||||
{"tint", in["specular_tint"]},
|
|
||||||
{"ior", ior},
|
|
||||||
{"scatter_mode", val(std::string("R"))},
|
|
||||||
{"roughness", n_main_roughness},
|
|
||||||
{"normal", normal},
|
|
||||||
{"tangent", n_main_tangent}});
|
|
||||||
|
|
||||||
NodeItem n_coat_affected_transmission_roughness = create_node(
|
|
||||||
"mix",
|
|
||||||
NodeItem::Type::Float,
|
|
||||||
{{"fg", val(1.0f)},
|
|
||||||
{"bg", (roughness + roughness).clamp(0.0f, 1.0f)},
|
|
||||||
{"mix", n_coat_affect_roughness_multiply2}});
|
|
||||||
|
|
||||||
NodeItem n_transmission_roughness = create_node(
|
|
||||||
"roughness_anisotropy",
|
|
||||||
NodeItem::Type::Vector2,
|
|
||||||
{{"roughness", n_coat_affected_transmission_roughness}, {"anisotropy", anisotropy}});
|
|
||||||
|
|
||||||
NodeItem n_transmission_bsdf = create_node("dielectric_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"tint", base_color},
|
|
||||||
{"ior", ior},
|
|
||||||
{"roughness", n_transmission_roughness},
|
|
||||||
{"normal", normal},
|
|
||||||
{"tangent", n_main_tangent}});
|
|
||||||
|
|
||||||
NodeItem n_coat_gamma = coat.clamp(0.0f, 1.0f) * val(0.0f) + val(1.0f);
|
|
||||||
NodeItem n_coat_affected_subsurface_color = base_color.max(val(0.0f)) ^ n_coat_gamma;
|
|
||||||
NodeItem n_translucent_bsdf = create_node(
|
|
||||||
"translucent_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"color", n_coat_affected_subsurface_color}, {"normal", normal}});
|
|
||||||
|
|
||||||
NodeItem n_subsurface_bsdf = create_node(
|
|
||||||
"subsurface_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"color", n_coat_affected_subsurface_color},
|
|
||||||
{"radius", in["subsurface_radius"] * in["subsurface_scale"]},
|
|
||||||
{"anisotropy", in["subsurface_anisotropy"]},
|
|
||||||
{"normal", normal}});
|
|
||||||
|
|
||||||
NodeItem n_selected_subsurface_bsdf = create_node(
|
|
||||||
"mix",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"fg", n_translucent_bsdf}, {"bg", n_subsurface_bsdf}, {"mix", val(0.0f)}});
|
|
||||||
|
|
||||||
NodeItem n_sheen_bsdf = create_node("sheen_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"weight", in["sheen"]},
|
|
||||||
{"color", in["sheen_tint"]},
|
|
||||||
{"roughness", in["sheen_roughness"]},
|
|
||||||
{"normal", normal}});
|
|
||||||
|
|
||||||
NodeItem n_diffuse_bsdf = create_node("oren_nayar_diffuse_bsdf",
|
|
||||||
NodeItem::Type::BSDF,
|
NodeItem::Type::BSDF,
|
||||||
{{"color", base_color.max(val(0.0f)) ^ n_coat_gamma},
|
{{"ior", n_ior_out},
|
||||||
{"roughness", roughness},
|
{"extinction", n_extinction_out},
|
||||||
{"weight", val(1.0f)},
|
{"roughness", n_main_roughness},
|
||||||
|
{"normal", normal},
|
||||||
|
{"tangent", n_main_tangent}});
|
||||||
|
|
||||||
|
NodeItem n_specular_bsdf = create_node("dielectric_bsdf",
|
||||||
|
NodeItem::Type::BSDF,
|
||||||
|
{{"weight", specular},
|
||||||
|
{"tint", in["specular_tint"]},
|
||||||
|
{"ior", ior},
|
||||||
|
{"scatter_mode", val(std::string("R"))},
|
||||||
|
{"roughness", n_main_roughness},
|
||||||
|
{"normal", normal},
|
||||||
|
{"tangent", n_main_tangent}});
|
||||||
|
|
||||||
|
NodeItem n_coat_affected_transmission_roughness = n_coat_affect_roughness_multiply2.mix(
|
||||||
|
(roughness + roughness).clamp(), val(1.0f));
|
||||||
|
|
||||||
|
NodeItem n_transmission_roughness = create_node(
|
||||||
|
"roughness_anisotropy",
|
||||||
|
NodeItem::Type::Vector2,
|
||||||
|
{{"roughness", n_coat_affected_transmission_roughness}, {"anisotropy", anisotropy}});
|
||||||
|
|
||||||
|
NodeItem n_transmission_bsdf = create_node("dielectric_bsdf",
|
||||||
|
NodeItem::Type::BSDF,
|
||||||
|
{{"tint", base_color},
|
||||||
|
{"ior", ior},
|
||||||
|
{"roughness", n_transmission_roughness},
|
||||||
|
{"normal", normal},
|
||||||
|
{"tangent", n_main_tangent}});
|
||||||
|
|
||||||
|
NodeItem n_coat_gamma = coat.clamp(0.0f, 1.0f) * val(0.0f) + val(1.0f);
|
||||||
|
NodeItem n_coat_affected_subsurface_color = base_color.max(val(0.0f)) ^ n_coat_gamma;
|
||||||
|
NodeItem n_translucent_bsdf = create_node(
|
||||||
|
"translucent_bsdf",
|
||||||
|
NodeItem::Type::BSDF,
|
||||||
|
{{"color", n_coat_affected_subsurface_color}, {"normal", normal}});
|
||||||
|
|
||||||
|
NodeItem n_subsurface_bsdf = create_node(
|
||||||
|
"subsurface_bsdf",
|
||||||
|
NodeItem::Type::BSDF,
|
||||||
|
{{"color", n_coat_affected_subsurface_color},
|
||||||
|
{"radius", in["subsurface_radius"] * in["subsurface_scale"]},
|
||||||
|
{"anisotropy", in["subsurface_anisotropy"]},
|
||||||
|
{"normal", normal}});
|
||||||
|
|
||||||
|
NodeItem n_sheen_bsdf = create_node("sheen_bsdf",
|
||||||
|
NodeItem::Type::BSDF,
|
||||||
|
{{"weight", in["sheen"]},
|
||||||
|
{"color", in["sheen_tint"]},
|
||||||
|
{"roughness", in["sheen_roughness"]},
|
||||||
{"normal", normal}});
|
{"normal", normal}});
|
||||||
|
|
||||||
NodeItem n_subsurface_mix = create_node(
|
NodeItem n_diffuse_bsdf = create_node("oren_nayar_diffuse_bsdf",
|
||||||
"mix",
|
NodeItem::Type::BSDF,
|
||||||
NodeItem::Type::BSDF,
|
{{"color", base_color.max(val(0.0f)) ^ n_coat_gamma},
|
||||||
{{"fg", n_selected_subsurface_bsdf}, {"bg", n_diffuse_bsdf}, {"mix", in["subsurface"]}});
|
{"roughness", roughness},
|
||||||
|
{"weight", val(1.0f)},
|
||||||
|
{"normal", normal}});
|
||||||
|
|
||||||
NodeItem n_sheen_layer = create_node(
|
NodeItem n_subsurface_mix = in["subsurface"].mix(n_diffuse_bsdf, n_subsurface_bsdf);
|
||||||
"layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}});
|
|
||||||
|
|
||||||
NodeItem n_transmission_mix = create_node(
|
NodeItem n_sheen_layer = create_node(
|
||||||
"mix",
|
"layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}});
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"fg", n_transmission_bsdf}, {"bg", n_sheen_layer}, {"mix", in["transmission"]}});
|
|
||||||
|
|
||||||
NodeItem n_specular_layer = create_node(
|
NodeItem n_transmission_mix = in["transmission"].mix(n_sheen_layer, n_transmission_bsdf);
|
||||||
"layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}});
|
|
||||||
|
|
||||||
NodeItem n_metalness_mix = create_node(
|
NodeItem n_specular_layer = create_node(
|
||||||
"mix",
|
"layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}});
|
||||||
NodeItem::Type::BSDF,
|
|
||||||
{{"fg", n_metal_bsdf}, {"bg", n_specular_layer}, {"mix", in["metallic"]}});
|
|
||||||
|
|
||||||
NodeItem n_thin_film_layer = create_node(
|
NodeItem n_metalness_mix = in["metallic"].mix(n_specular_layer, n_metal_bsdf);
|
||||||
"layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}});
|
|
||||||
|
|
||||||
NodeItem n_opacity_luminance = create_node(
|
NodeItem n_thin_film_layer = create_node(
|
||||||
"luminance", NodeItem::Type::Color3, {{"in", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))}});
|
"layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}});
|
||||||
|
|
||||||
NodeItem n_coat_attenuation = create_node("mix",
|
NodeItem n_opacity_luminance = create_node(
|
||||||
NodeItem::Type::Color3,
|
"luminance", NodeItem::Type::Color3, {{"in", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))}});
|
||||||
{{"fg", in["coat_tint"]},
|
|
||||||
{"bg", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))},
|
|
||||||
{"mix", coat}});
|
|
||||||
|
|
||||||
res = create_node("layer",
|
NodeItem n_coat_attenuation = coat.mix(val(MaterialX::Color3(1.0f, 1.0f, 1.0f)),
|
||||||
NodeItem::Type::BSDF,
|
in["coat_tint"]);
|
||||||
{{"top", n_coat_bsdf}, {"base", n_thin_film_layer * n_coat_attenuation}});
|
|
||||||
|
res = create_node("layer",
|
||||||
|
NodeItem::Type::BSDF,
|
||||||
|
{{"top", n_coat_bsdf}, {"base", n_thin_film_layer * n_coat_attenuation}});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NodeItem::Type::EDF: {
|
||||||
|
auto in = edf_inputs();
|
||||||
|
res = create_node(
|
||||||
|
"uniform_edf", NodeItem::Type::EDF, {{"color", in["emission_color"] * in["emission"]}});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NodeItem::Type::SurfaceShader: {
|
||||||
|
auto in = bsdf_inputs();
|
||||||
|
auto e_in = edf_inputs();
|
||||||
|
in.insert(e_in.begin(), e_in.end());
|
||||||
|
|
||||||
|
NodeItem roughness = in["roughness"];
|
||||||
|
NodeItem base_color = in["base_color"];
|
||||||
|
NodeItem anisotropic = in["anisotropic"];
|
||||||
|
NodeItem rotation = in["anisotropic_rotation"];
|
||||||
|
|
||||||
|
res = create_node("standard_surface",
|
||||||
|
NodeItem::Type::SurfaceShader,
|
||||||
|
{{"base", val(1.0f)},
|
||||||
|
{"base_color", base_color},
|
||||||
|
{"diffuse_roughness", roughness},
|
||||||
|
{"metalness", in["metallic"]},
|
||||||
|
{"specular", in["specular"]},
|
||||||
|
{"specular_color", in["specular_tint"]},
|
||||||
|
{"specular_roughness", roughness},
|
||||||
|
{"specular_IOR", in["ior"]},
|
||||||
|
{"specular_anisotropy", anisotropic},
|
||||||
|
{"specular_rotation", rotation},
|
||||||
|
{"transmission", in["transmission"]},
|
||||||
|
{"transmission_color", base_color},
|
||||||
|
{"transmission_extra_roughness", roughness},
|
||||||
|
{"subsurface", in["subsurface"]},
|
||||||
|
{"subsurface_color", base_color},
|
||||||
|
{"subsurface_radius", in["subsurface_radius"] * in["subsurface_scale"]},
|
||||||
|
{"subsurface_anisotropy", in["subsurface_anisotropy"]},
|
||||||
|
{"sheen", in["sheen"]},
|
||||||
|
{"sheen_color", in["sheen_tint"]},
|
||||||
|
{"sheen_roughness", in["sheen_roughness"]},
|
||||||
|
{"coat", in["coat"]},
|
||||||
|
{"coat_color", in["coat_tint"]},
|
||||||
|
{"coat_roughness", in["coat_roughness"]},
|
||||||
|
{"coat_IOR", in["coat_ior"]},
|
||||||
|
{"coat_anisotropy", anisotropic},
|
||||||
|
{"coat_rotation", rotation},
|
||||||
|
{"coat_normal", in["coat_normal"]},
|
||||||
|
{"emission", in["emission"]},
|
||||||
|
{"emission_color", in["emission_color"]},
|
||||||
|
{"normal", in["normal"]},
|
||||||
|
{"tangent", in["tangent"]}});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
else if (to_type_ == NodeItem::Type::EDF) {
|
|
||||||
auto in = edf_inputs();
|
|
||||||
|
|
||||||
res = create_node(
|
|
||||||
"uniform_edf", NodeItem::Type::EDF, {{"color", in["emission_color"] * in["emission"]}});
|
|
||||||
}
|
|
||||||
else if (to_type_ == NodeItem::Type::SurfaceShader) {
|
|
||||||
auto in = bsdf_inputs();
|
|
||||||
auto e_in = edf_inputs();
|
|
||||||
in.insert(e_in.begin(), e_in.end());
|
|
||||||
|
|
||||||
NodeItem roughness = in["roughness"];
|
|
||||||
NodeItem base_color = in["base_color"];
|
|
||||||
NodeItem anisotropic = in["anisotropic"];
|
|
||||||
NodeItem rotation = in["anisotropic_rotation"];
|
|
||||||
|
|
||||||
res = create_node("standard_surface",
|
|
||||||
NodeItem::Type::SurfaceShader,
|
|
||||||
{{"base", val(1.0f)},
|
|
||||||
{"base_color", base_color},
|
|
||||||
{"diffuse_roughness", roughness},
|
|
||||||
{"metalness", in["metallic"]},
|
|
||||||
{"specular", in["specular"]},
|
|
||||||
{"specular_color", in["specular_tint"]},
|
|
||||||
{"specular_roughness", roughness},
|
|
||||||
{"specular_IOR", in["ior"]},
|
|
||||||
{"specular_anisotropy", anisotropic},
|
|
||||||
{"specular_rotation", rotation},
|
|
||||||
{"transmission", in["transmission"]},
|
|
||||||
{"transmission_color", base_color},
|
|
||||||
{"transmission_extra_roughness", roughness},
|
|
||||||
{"subsurface", in["subsurface"]},
|
|
||||||
{"subsurface_color", base_color},
|
|
||||||
{"subsurface_radius", in["subsurface_radius"] * in["subsurface_scale"]},
|
|
||||||
{"subsurface_anisotropy", in["subsurface_anisotropy"]},
|
|
||||||
{"sheen", in["sheen"]},
|
|
||||||
{"sheen_color", in["sheen_tint"]},
|
|
||||||
{"sheen_roughness", in["sheen_roughness"]},
|
|
||||||
{"coat", in["coat"]},
|
|
||||||
{"coat_color", in["coat_tint"]},
|
|
||||||
{"coat_roughness", in["coat_roughness"]},
|
|
||||||
{"coat_IOR", in["coat_ior"]},
|
|
||||||
{"coat_anisotropy", anisotropic},
|
|
||||||
{"coat_rotation", rotation},
|
|
||||||
{"coat_normal", in["coat_normal"]},
|
|
||||||
{"emission", in["emission"]},
|
|
||||||
{"emission_color", in["emission_color"]},
|
|
||||||
{"normal", in["normal"]},
|
|
||||||
{"tangent", in["tangent"]}});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,6 +22,7 @@ static int node_shader_gpu_gamma(GPUMaterial *mat,
|
|||||||
{
|
{
|
||||||
return GPU_stack_link(mat, node, "node_gamma", in, out);
|
return GPU_stack_link(mat, node, "node_gamma", in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
{
|
{
|
||||||
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
|
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
|
||||||
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
|
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
|
||||||
return fac.blend(color, val(1.0f) - color);
|
return fac.mix(color, val(1.0f) - color);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -77,37 +77,31 @@ static void node_shader_update_mapping(bNodeTree *ntree, bNode *node)
|
|||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
NodeItem res = empty();
|
NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3);
|
||||||
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
|
||||||
|
|
||||||
if (!vector) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Vector3);
|
NodeItem scale = get_input_value("Scale", NodeItem::Type::Vector3);
|
||||||
NodeItem location = get_input_value("Location", NodeItem::Type::Vector3);
|
NodeItem rotation = get_input_value("Rotation", NodeItem::Type::Vector3) *
|
||||||
NodeItem rotation = (get_input_value("Rotation", NodeItem::Type::Vector3) *
|
val(float(180.0f / M_PI));
|
||||||
val(float(180.0f / M_PI)));
|
|
||||||
|
|
||||||
switch (node_->custom1) {
|
int type = node_->custom1;
|
||||||
case NODE_MAPPING_TYPE_POINT:
|
switch (type) {
|
||||||
res = (vector * scale).rotate3d(rotation) + location;
|
case NODE_MAPPING_TYPE_POINT: {
|
||||||
break;
|
NodeItem location = get_input_value("Location", NodeItem::Type::Vector3);
|
||||||
case NODE_MAPPING_TYPE_TEXTURE:
|
return (vector * scale).rotate(rotation) + location;
|
||||||
res = (vector - location).rotate3d(rotation, true) / scale;
|
}
|
||||||
break;
|
case NODE_MAPPING_TYPE_TEXTURE: {
|
||||||
case NODE_MAPPING_TYPE_VECTOR:
|
NodeItem location = get_input_value("Location", NodeItem::Type::Vector3);
|
||||||
res = (vector * scale).rotate3d(rotation * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f)));
|
return (vector - location).rotate(rotation, true) / scale;
|
||||||
break;
|
}
|
||||||
case NODE_MAPPING_TYPE_NORMAL:
|
case NODE_MAPPING_TYPE_VECTOR: {
|
||||||
res = create_node(
|
return (vector * scale).rotate(rotation * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f)));
|
||||||
"normalize", NodeItem::Type::Vector3, {{"in", (vector / scale).rotate3d(rotation)}});
|
}
|
||||||
break;
|
case NODE_MAPPING_TYPE_NORMAL: {
|
||||||
|
return (vector / scale).rotate(rotation).normalize();
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
|
return empty();
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -543,6 +543,58 @@ static void sh_node_mix_build_multi_function(NodeMultiFunctionBuilder &builder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
|
#ifdef WITH_MATERIALX
|
||||||
|
{
|
||||||
|
const NodeShaderMix *data = (NodeShaderMix *)node_->storage;
|
||||||
|
|
||||||
|
NodeItem factor = empty();
|
||||||
|
NodeItem value1 = empty();
|
||||||
|
NodeItem value2 = empty();
|
||||||
|
switch (data->data_type) {
|
||||||
|
case SOCK_FLOAT:
|
||||||
|
factor = get_input_value(0, NodeItem::Type::Float);
|
||||||
|
value1 = get_input_value(2, NodeItem::Type::Float);
|
||||||
|
value2 = get_input_value(3, NodeItem::Type::Float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOCK_VECTOR:
|
||||||
|
if (data->factor_mode == NODE_MIX_MODE_UNIFORM) {
|
||||||
|
factor = get_input_value(0, NodeItem::Type::Float);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
factor = get_input_value(1, NodeItem::Type::Vector3);
|
||||||
|
}
|
||||||
|
value1 = get_input_value(4, NodeItem::Type::Vector3);
|
||||||
|
value2 = get_input_value(5, NodeItem::Type::Vector3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOCK_RGBA:
|
||||||
|
factor = get_input_value(0, NodeItem::Type::Float);
|
||||||
|
value1 = get_input_value(6, NodeItem::Type::Color4);
|
||||||
|
value2 = get_input_value(7, NodeItem::Type::Color4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->clamp_factor) {
|
||||||
|
factor = factor.clamp();
|
||||||
|
}
|
||||||
|
NodeItem res = factor.mix(value1, value2);
|
||||||
|
if (data->data_type == SOCK_RGBA) {
|
||||||
|
/* TODO: Apply data->blend_type */
|
||||||
|
|
||||||
|
if (data->clamp_result) {
|
||||||
|
res = res.clamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
NODE_SHADER_MATERIALX_END
|
||||||
|
|
||||||
} // namespace blender::nodes::node_sh_mix_cc
|
} // namespace blender::nodes::node_sh_mix_cc
|
||||||
|
|
||||||
void register_node_type_sh_mix()
|
void register_node_type_sh_mix()
|
||||||
@ -562,5 +614,7 @@ void register_node_type_sh_mix()
|
|||||||
ntype.draw_buttons = file_ns::sh_node_mix_layout;
|
ntype.draw_buttons = file_ns::sh_node_mix_layout;
|
||||||
ntype.labelfunc = file_ns::sh_node_mix_label;
|
ntype.labelfunc = file_ns::sh_node_mix_label;
|
||||||
ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches;
|
ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches;
|
||||||
|
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||||
|
|
||||||
nodeRegisterType(&ntype);
|
nodeRegisterType(&ntype);
|
||||||
}
|
}
|
||||||
|
@ -150,15 +150,6 @@ static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &build
|
|||||||
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
|
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_SHADER_MATERIALX_BEGIN
|
|
||||||
#ifdef WITH_MATERIALX
|
|
||||||
{
|
|
||||||
/* TODO: Implement */
|
|
||||||
return empty();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
NODE_SHADER_MATERIALX_END
|
|
||||||
|
|
||||||
} // namespace blender::nodes::node_shader_mix_rgb_cc
|
} // namespace blender::nodes::node_shader_mix_rgb_cc
|
||||||
|
|
||||||
void register_node_type_sh_mix_rgb()
|
void register_node_type_sh_mix_rgb()
|
||||||
@ -173,6 +164,5 @@ void register_node_type_sh_mix_rgb()
|
|||||||
ntype.gpu_fn = file_ns::gpu_shader_mix_rgb;
|
ntype.gpu_fn = file_ns::gpu_shader_mix_rgb;
|
||||||
ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
|
ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
|
||||||
ntype.gather_link_search_ops = nullptr;
|
ntype.gather_link_search_ops = nullptr;
|
||||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
|
||||||
nodeRegisterType(&ntype);
|
nodeRegisterType(&ntype);
|
||||||
}
|
}
|
||||||
|
@ -26,37 +26,25 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
|
|||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
NodeItem res = empty();
|
if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) {
|
||||||
switch (to_type_) {
|
return empty();
|
||||||
case NodeItem::Type::BSDF:
|
|
||||||
case NodeItem::Type::EDF: {
|
|
||||||
NodeItem fac = get_input_value(0, NodeItem::Type::Float);
|
|
||||||
NodeItem shader1 = get_input_link(1, to_type_);
|
|
||||||
NodeItem shader2 = get_input_link(2, to_type_);
|
|
||||||
|
|
||||||
if (shader1 && !shader2) {
|
|
||||||
res = shader1 * (val(1.0f) - fac);
|
|
||||||
}
|
|
||||||
else if (!shader1 && shader2) {
|
|
||||||
res = shader2 * fac;
|
|
||||||
}
|
|
||||||
else if (shader1 && shader2) {
|
|
||||||
res = create_node("mix", to_type_, {{"fg", shader2}, {"bg", shader1}, {"mix", fac}});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NodeItem::Type::SurfaceShader: {
|
|
||||||
/* SurfaceShaders can't be mixed, returning the first one connected */
|
|
||||||
res = get_input_link(1, NodeItem::Type::SurfaceShader);
|
|
||||||
if (!res) {
|
|
||||||
res = get_input_link(2, NodeItem::Type::SurfaceShader);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
|
NodeItem shader1 = get_input_link(1, to_type_);
|
||||||
|
NodeItem shader2 = get_input_link(2, to_type_);
|
||||||
|
if (!shader1 && !shader2) {
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeItem fac = get_input_value(0, NodeItem::Type::Float);
|
||||||
|
|
||||||
|
if (shader1 && !shader2) {
|
||||||
|
return shader1 * (val(1.0f) - fac);
|
||||||
|
}
|
||||||
|
if (!shader1 && shader2) {
|
||||||
|
return shader2 * fac;
|
||||||
|
}
|
||||||
|
return fac.mix(shader1, shader2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -46,20 +46,19 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
|
|||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
NodeItem bsdf = get_input_link("Surface", NodeItem::Type::BSDF);
|
NodeItem surface = get_input_link("Surface", NodeItem::Type::SurfaceShader);
|
||||||
NodeItem edf = get_input_link("Surface", NodeItem::Type::EDF);
|
if (!surface) {
|
||||||
NodeItem surface = empty();
|
NodeItem bsdf = get_input_link("Surface", NodeItem::Type::BSDF);
|
||||||
if (bsdf || edf) {
|
NodeItem edf = get_input_link("Surface", NodeItem::Type::EDF);
|
||||||
surface = create_node("surface", NodeItem::Type::SurfaceShader);
|
if (bsdf || edf) {
|
||||||
if (bsdf) {
|
surface = create_node("surface", NodeItem::Type::SurfaceShader);
|
||||||
surface.set_input("bsdf", bsdf);
|
if (bsdf) {
|
||||||
|
surface.set_input("bsdf", bsdf);
|
||||||
|
}
|
||||||
|
if (edf) {
|
||||||
|
surface.set_input("edf", edf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (edf) {
|
|
||||||
surface.set_input("edf", edf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
surface = get_input_link("Surface", NodeItem::Type::SurfaceShader);
|
|
||||||
}
|
}
|
||||||
return create_node("surfacematerial", NodeItem::Type::Material, {{"surfaceshader", surface}});
|
return create_node("surfacematerial", NodeItem::Type::Material, {{"surfaceshader", surface}});
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
}
|
}
|
||||||
|
|
||||||
int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2;
|
int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2;
|
||||||
return convert.extract(index);
|
return convert[index];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -95,7 +95,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
{
|
{
|
||||||
NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3);
|
NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3);
|
||||||
int index = STREQ(socket_out_->name, "X") ? 0 : STREQ(socket_out_->name, "Y") ? 1 : 2;
|
int index = STREQ(socket_out_->name, "X") ? 0 : STREQ(socket_out_->name, "Y") ? 1 : 2;
|
||||||
return vector.extract(index);
|
return vector[index];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -118,7 +118,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
||||||
|
|
||||||
vector = (vector * scale) % val(2.0f);
|
vector = (vector * scale) % val(2.0f);
|
||||||
return (vector.extract(0).floor() + vector.extract(1).floor())
|
return (vector[0].floor() + vector[1].floor())
|
||||||
.if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2);
|
.if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -160,21 +160,21 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
|
|
||||||
switch (gradient_type) {
|
switch (gradient_type) {
|
||||||
case SHD_BLEND_LINEAR:
|
case SHD_BLEND_LINEAR:
|
||||||
res = vector.extract(0);
|
res = vector[0];
|
||||||
break;
|
break;
|
||||||
case SHD_BLEND_QUADRATIC:
|
case SHD_BLEND_QUADRATIC:
|
||||||
res = vector.extract(0);
|
res = vector[0];
|
||||||
res = res * res;
|
res = res * res;
|
||||||
break;
|
break;
|
||||||
case SHD_BLEND_EASING:
|
case SHD_BLEND_EASING:
|
||||||
res = vector.extract(0).clamp(val(0.0f), val(1.0f));
|
res = vector[0].clamp();
|
||||||
res = res * res * (val(3.0f) - val(2.0f) * res);
|
res = res * res * (val(3.0f) - val(2.0f) * res);
|
||||||
break;
|
break;
|
||||||
case SHD_BLEND_DIAGONAL:
|
case SHD_BLEND_DIAGONAL:
|
||||||
res = (vector.extract(0) + vector.extract(1)) * val(0.5f);
|
res = (vector[0] + vector[1]) * val(0.5f);
|
||||||
break;
|
break;
|
||||||
case SHD_BLEND_RADIAL:
|
case SHD_BLEND_RADIAL:
|
||||||
res = vector.extract(1).atan2(vector.extract(0)) / (val(float(M_PI * 2.0f))) + val(0.5f);
|
res = vector[1].atan2(vector[0]) / (val(float(M_PI * 2.0f))) + val(0.5f);
|
||||||
break;
|
break;
|
||||||
case SHD_BLEND_QUADRATIC_SPHERE:
|
case SHD_BLEND_QUADRATIC_SPHERE:
|
||||||
res = (val(1.0f) - vector.dotproduct(vector).sqrt()).max(val(0.0f));
|
res = (val(1.0f) - vector.dotproduct(vector).sqrt()).max(val(0.0f));
|
||||||
|
@ -248,7 +248,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (STREQ(socket_out_->name, "Alpha")) {
|
if (STREQ(socket_out_->name, "Alpha")) {
|
||||||
res = res.extract(3);
|
res = res[3];
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -223,59 +223,59 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
NodeTexWave *tex = (NodeTexWave *)node_->storage;
|
NodeTexWave *tex = (NodeTexWave *)node_->storage;
|
||||||
const int wave_type = tex->wave_type;
|
|
||||||
const int bands_direction = tex->bands_direction;
|
|
||||||
const int rings_direction = tex->rings_direction;
|
|
||||||
const int wave_profile = tex->wave_profile;
|
|
||||||
|
|
||||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
||||||
NodeItem distortion = get_input_value("Distortion", NodeItem::Type::Float) /
|
NodeItem distortion = get_input_value("Distortion", NodeItem::Type::Float);
|
||||||
val(10.0f); // noise adjusment to get result as Cycles
|
NodeItem detail = get_input_default("Detail", NodeItem::Type::Float);
|
||||||
NodeItem detail = get_input_value("Detail", NodeItem::Type::Float);
|
NodeItem detail_scale = get_input_value("Detail Scale", NodeItem::Type::Float);
|
||||||
NodeItem detail_scale = get_input_value("Detail Scale", NodeItem::Type::Float) *
|
|
||||||
val(10.0f); // noise adjusment to get result as Cycles
|
|
||||||
NodeItem detail_rough = get_input_value("Detail Roughness", NodeItem::Type::Float);
|
NodeItem detail_rough = get_input_value("Detail Roughness", NodeItem::Type::Float);
|
||||||
NodeItem phase_offset = get_input_value("Phase Offset", NodeItem::Type::Float);
|
NodeItem phase_offset = get_input_value("Phase Offset", NodeItem::Type::Float);
|
||||||
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
||||||
if (!vector) {
|
if (!vector) {
|
||||||
vector = texcoord_node();
|
vector = texcoord_node(NodeItem::Type::Vector3);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem p = vector * scale;
|
/* adjusment to get result as Cycles */
|
||||||
p = (p + val(0.000001f)) * val(0.999999f);
|
distortion = distortion * val(10.0f);
|
||||||
NodeItem n = val(0.0f);
|
detail_scale = detail_scale * val(10.0f);
|
||||||
NodeItem value = val(0.0f);
|
|
||||||
|
|
||||||
switch (wave_type) {
|
NodeItem pos = vector * scale;
|
||||||
|
NodeItem fractal = create_node("fractal3d",
|
||||||
|
NodeItem::Type::Float,
|
||||||
|
{{"position", pos},
|
||||||
|
{"octaves", val(int(detail.value->asA<float>()))},
|
||||||
|
{"lacunarity", val(2.0f)}});
|
||||||
|
NodeItem value = val(0.0f);
|
||||||
|
switch (tex->wave_type) {
|
||||||
case SHD_WAVE_BANDS:
|
case SHD_WAVE_BANDS:
|
||||||
switch (bands_direction) {
|
switch (tex->bands_direction) {
|
||||||
case SHD_WAVE_BANDS_DIRECTION_X:
|
case SHD_WAVE_BANDS_DIRECTION_X:
|
||||||
n = p.extract(0) * val(20.0f);
|
value = pos[0] * val(20.0f);
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_BANDS_DIRECTION_Y:
|
case SHD_WAVE_BANDS_DIRECTION_Y:
|
||||||
n = p.extract(1) * val(20.0f);
|
value = pos[1] * val(20.0f);
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_BANDS_DIRECTION_Z:
|
case SHD_WAVE_BANDS_DIRECTION_Z:
|
||||||
n = p.extract(2) * val(20.0f);
|
value = pos[2] * val(20.0f);
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_BANDS_DIRECTION_DIAGONAL:
|
case SHD_WAVE_BANDS_DIRECTION_DIAGONAL:
|
||||||
n = (p.extract(0) + p.extract(1) + p.extract(2)) * val(10.0f);
|
value = (pos[0] + pos[1] + pos[2]) * val(10.0f);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_RINGS:
|
case SHD_WAVE_RINGS:
|
||||||
NodeItem rp = p;
|
NodeItem rpos = pos;
|
||||||
switch (rings_direction) {
|
switch (tex->rings_direction) {
|
||||||
case SHD_WAVE_RINGS_DIRECTION_X:
|
case SHD_WAVE_RINGS_DIRECTION_X:
|
||||||
rp = rp * val(MaterialX::Vector3(0.0f, 1.0f, 1.0f));
|
rpos = pos * val(MaterialX::Vector3(0.0f, 1.0f, 1.0f));
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_RINGS_DIRECTION_Y:
|
case SHD_WAVE_RINGS_DIRECTION_Y:
|
||||||
rp = rp * val(MaterialX::Vector3(1.0f, 0.0f, 1.0f));
|
rpos = pos * val(MaterialX::Vector3(1.0f, 0.0f, 1.0f));
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_RINGS_DIRECTION_Z:
|
case SHD_WAVE_RINGS_DIRECTION_Z:
|
||||||
rp = rp * val(MaterialX::Vector3(1.0f, 1.0f, 0.0f));
|
rpos = pos * val(MaterialX::Vector3(1.0f, 1.0f, 0.0f));
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_RINGS_DIRECTION_SPHERICAL:
|
case SHD_WAVE_RINGS_DIRECTION_SPHERICAL:
|
||||||
/* Ignore. */
|
/* Ignore. */
|
||||||
@ -283,33 +283,28 @@ NODE_SHADER_MATERIALX_BEGIN
|
|||||||
default:
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
n = rp.dotproduct(rp).sqrt() * val(20.0f);
|
value = rpos.length() * val(20.0f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n = n + phase_offset;
|
value = value + phase_offset + distortion * detail_scale * fractal;
|
||||||
n = n + distortion * detail_scale *
|
|
||||||
create_node("fractal3d",
|
|
||||||
NodeItem::Type::Float,
|
|
||||||
{{"position", p},
|
|
||||||
{"octaves", val(int(detail.value->asA<float>()))},
|
|
||||||
{"lacunarity", val(2.0f)}});
|
|
||||||
|
|
||||||
switch (wave_profile) {
|
NodeItem res = empty();
|
||||||
|
switch (tex->wave_profile) {
|
||||||
case SHD_WAVE_PROFILE_SIN:
|
case SHD_WAVE_PROFILE_SIN:
|
||||||
value = val(0.5f) + val(0.5f) * (n - val(float(M_PI_2))).sin();
|
res = val(0.5f) + val(0.5f) * (value - val(float(M_PI_2))).sin();
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_PROFILE_SAW:
|
case SHD_WAVE_PROFILE_SAW:
|
||||||
n = n / val(float(M_PI * 2.0f));
|
value = value / val(float(M_PI * 2.0f));
|
||||||
value = n - n.floor();
|
res = value - value.floor();
|
||||||
break;
|
break;
|
||||||
case SHD_WAVE_PROFILE_TRI:
|
case SHD_WAVE_PROFILE_TRI:
|
||||||
n = n / val(float(M_PI * 2.0f));
|
value = value / val(float(M_PI * 2.0f));
|
||||||
value = (n - (n + val(0.5f)).floor()).abs() * val(2.0f);
|
res = (value - (value + val(0.5f)).floor()).abs() * val(2.0f);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
}
|
}
|
||||||
return value;
|
return res;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
@ -215,62 +215,42 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
|
|||||||
NODE_SHADER_MATERIALX_BEGIN
|
NODE_SHADER_MATERIALX_BEGIN
|
||||||
#ifdef WITH_MATERIALX
|
#ifdef WITH_MATERIALX
|
||||||
{
|
{
|
||||||
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
int mode = node_->custom1;
|
||||||
|
bool invert = node_->custom2;
|
||||||
|
|
||||||
if (!vector) {
|
NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3);
|
||||||
return empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem angle = empty();
|
|
||||||
NodeItem axis = empty();
|
|
||||||
NodeItem center = get_input_value("Center", NodeItem::Type::Vector3) *
|
NodeItem center = get_input_value("Center", NodeItem::Type::Vector3) *
|
||||||
BogdanNagirniak marked this conversation as resolved
Outdated
Vasyl Pidhirskyi
commented
To perform the same result as Blender it requires invert Z. To perform the same result as Blender it requires invert Z.
`NodeItem center = get_input_value("Center", NodeItem::Type::Vector3) * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f))`
|
|||||||
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
||||||
NodeItem res = vector - center;
|
vector = vector - center;
|
||||||
int mode = node_->custom1;
|
|
||||||
bool invert = node_->custom1;
|
|
||||||
|
|
||||||
if (mode == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
|
if (mode == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
|
||||||
angle = get_input_value("Rotation", NodeItem::Type::Vector3);
|
NodeItem rotation = get_input_value("Rotation", NodeItem::Type::Vector3) *
|
||||||
angle = angle * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f) * 180.0f / M_PI);
|
||||||
}
|
|
||||||
else {
|
return vector.rotate(invert ? -rotation : rotation, invert) + center;
|
||||||
angle = get_input_value("Angle", NodeItem::Type::Float);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
angle = angle * val(float(180.0f / M_PI));
|
NodeItem angle = get_input_value("Angle", NodeItem::Type::Float) * val(float(180.0f / M_PI));
|
||||||
angle = invert ? angle * val(-1.0f) : angle;
|
NodeItem axis = empty();
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
|
case NODE_VECTOR_ROTATE_TYPE_AXIS:
|
||||||
return res.rotate3d(angle, invert) + center;
|
|
||||||
}
|
|
||||||
case NODE_VECTOR_ROTATE_TYPE_AXIS: {
|
|
||||||
axis = get_input_value("Axis", NodeItem::Type::Vector3) *
|
axis = get_input_value("Axis", NodeItem::Type::Vector3) *
|
||||||
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
||||||
break;
|
break;
|
||||||
}
|
case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
|
||||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_X: {
|
|
||||||
axis = val(MaterialX::Vector3(1.0f, 0.0f, 0.0f));
|
axis = val(MaterialX::Vector3(1.0f, 0.0f, 0.0f));
|
||||||
break;
|
break;
|
||||||
}
|
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
|
||||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: {
|
|
||||||
axis = val(MaterialX::Vector3(0.0f, 1.0f, 0.0f));
|
axis = val(MaterialX::Vector3(0.0f, 1.0f, 0.0f));
|
||||||
break;
|
break;
|
||||||
}
|
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
|
||||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: {
|
|
||||||
axis = val(MaterialX::Vector3(0.0f, 0.0f, -1.0f));
|
axis = val(MaterialX::Vector3(0.0f, 0.0f, -1.0f));
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
default: {
|
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
return vector;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return create_node("rotate3d",
|
return vector.rotate(invert ? -angle : angle, axis) + center;
|
||||||
NodeItem::Type::Vector3,
|
|
||||||
{{"in", res}, {"amount", angle}, {"axis", axis}}) +
|
|
||||||
center;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NODE_SHADER_MATERIALX_END
|
NODE_SHADER_MATERIALX_END
|
||||||
|
Loading…
Reference in New Issue
Block a user
Please take a look at code below
To fix
dotproduct
for values used.value->asA<MaterialX::...
insteadvalue->asA<MaterialX::...
.