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) *
|
||||||
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::...
.