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);
|
||||
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. */
|
||||
auto stage_str = [&stage]() {
|
||||
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); });
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!*this) {
|
||||
@ -226,6 +258,22 @@ NodeItem NodeItem::ceil() const
|
||||
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
|
||||
{
|
||||
return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); });
|
||||
@ -238,121 +286,182 @@ NodeItem NodeItem::max(const NodeItem &other) const
|
||||
|
||||
NodeItem NodeItem::dotproduct(const NodeItem &other) const
|
||||
{
|
||||
NodeItem d = arithmetic(
|
||||
other, "dotproduct", [](float a, float b) { return a * b; }, Type::Float);
|
||||
if (d.value) {
|
||||
if (value && other.value) {
|
||||
NodeItem d = *this * other;
|
||||
BogdanNagirniak marked this conversation as resolved
|
||||
float f = 0.0f;
|
||||
switch (d.type()) {
|
||||
case Type::Float: {
|
||||
f = value->asA<float>();
|
||||
f = d.value->asA<float>();
|
||||
break;
|
||||
}
|
||||
case Type::Vector2: {
|
||||
auto v = value->asA<MaterialX::Vector2>();
|
||||
auto v = d.value->asA<MaterialX::Vector2>();
|
||||
f = v[0] + v[1];
|
||||
break;
|
||||
}
|
||||
case Type::Vector3: {
|
||||
auto v = value->asA<MaterialX::Vector3>();
|
||||
auto v = d.value->asA<MaterialX::Vector3>();
|
||||
f = v[0] + v[1] + v[2];
|
||||
break;
|
||||
}
|
||||
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];
|
||||
break;
|
||||
}
|
||||
case Type::Color3: {
|
||||
auto v = value->asA<MaterialX::Color3>();
|
||||
auto v = d.value->asA<MaterialX::Color3>();
|
||||
f = v[0] + v[1] + v[2];
|
||||
break;
|
||||
}
|
||||
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];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
d.value = MaterialX::Value::createValue(f);
|
||||
}
|
||||
return d;
|
||||
return val(f);
|
||||
}
|
||||
|
||||
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
|
||||
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::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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
return arithmetic("sin", [](float a) { return std::sinf(a); });
|
||||
return to_vector().arithmetic("sin", [](float a) { return std::sinf(a); });
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return arithmetic("tan", [](float a) { return std::tanf(a); });
|
||||
return to_vector().arithmetic("tan", [](float a) { return std::tanf(a); });
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return arithmetic("acos", [](float a) { return std::acosf(a); });
|
||||
return to_vector().arithmetic("acos", [](float a) { return std::acosf(a); });
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
return (exp() - (-*this).exp()) / val(2.0f);
|
||||
NodeItem v = to_vector();
|
||||
return (v.exp() - (-v).exp()) / val(2.0f);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return sinh() / cosh();
|
||||
NodeItem v = to_vector();
|
||||
NodeItem a = v.exp();
|
||||
NodeItem b = (-v).exp();
|
||||
return (a - b) / (a + b);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return arithmetic("sqrt", [](float a) { return std::sqrtf(a); });
|
||||
return to_vector().arithmetic("sqrt", [](float a) { return std::sqrtf(a); });
|
||||
}
|
||||
|
||||
NodeItem NodeItem::sign() const
|
||||
@ -362,7 +471,7 @@ NodeItem NodeItem::sign() 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
|
||||
@ -380,7 +489,7 @@ NodeItem NodeItem::convert(Type to_type) const
|
||||
}
|
||||
|
||||
if (to_type == Type::Float) {
|
||||
return extract(0);
|
||||
return (*this)[0];
|
||||
}
|
||||
|
||||
/* Converting types which requires > 1 iteration */
|
||||
@ -548,6 +657,27 @@ NodeItem NodeItem::convert(Type to_type) const
|
||||
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,
|
||||
const NodeItem &other,
|
||||
const NodeItem &if_val,
|
||||
@ -606,35 +736,11 @@ NodeItem NodeItem::if_else(CompareOp op,
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
if (value) {
|
||||
@ -794,9 +900,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(f
|
||||
{
|
||||
NodeItem res = empty();
|
||||
Type type = this->type();
|
||||
if (!is_arithmetic(type)) {
|
||||
return res;
|
||||
}
|
||||
BLI_assert(is_arithmetic(type));
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
@ -838,15 +942,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(f
|
||||
}
|
||||
}
|
||||
else {
|
||||
NodeItem v = *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}});
|
||||
res = create_node(category, type, {{"in", *this}});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -10,9 +10,11 @@
|
||||
|
||||
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.
|
||||
* 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 {
|
||||
public:
|
||||
using Inputs = std::vector<std::pair<std::string, NodeItem>>;
|
||||
@ -21,22 +23,22 @@ class NodeItem {
|
||||
Any = 0,
|
||||
Empty,
|
||||
Multioutput,
|
||||
|
||||
/* Value types */
|
||||
String,
|
||||
Filename,
|
||||
Boolean,
|
||||
Integer,
|
||||
/* Block of arithmetic types. Ordered by type cast */
|
||||
|
||||
/* Arithmetic types. NOTE: Ordered by type cast */
|
||||
Float,
|
||||
Vector2,
|
||||
Vector3,
|
||||
Color3,
|
||||
Vector4,
|
||||
Color4,
|
||||
/* End of arithmetic types */
|
||||
|
||||
/* Shader types
|
||||
* NOTE: There are only supported types */
|
||||
/* Shader types. NOTE: There are only supported types */
|
||||
BSDF,
|
||||
EDF,
|
||||
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[](int index) const;
|
||||
bool operator==(const NodeItem &other) const;
|
||||
bool operator!=(const NodeItem &other) const;
|
||||
|
||||
@ -81,12 +84,16 @@ class NodeItem {
|
||||
NodeItem abs() const;
|
||||
NodeItem floor() const;
|
||||
NodeItem ceil() const;
|
||||
NodeItem length() const;
|
||||
NodeItem normalize() const;
|
||||
NodeItem min(const NodeItem &other) const;
|
||||
NodeItem max(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(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 cos() const;
|
||||
NodeItem tan() const;
|
||||
@ -102,15 +109,14 @@ class NodeItem {
|
||||
NodeItem sign() const;
|
||||
NodeItem exp() const;
|
||||
NodeItem convert(Type to_type) const;
|
||||
NodeItem to_vector() const;
|
||||
NodeItem if_else(CompareOp op,
|
||||
const NodeItem &other,
|
||||
const NodeItem &if_val,
|
||||
const NodeItem &else_val) const;
|
||||
NodeItem extract(const int index) const;
|
||||
|
||||
/* Useful functions */
|
||||
NodeItem empty() const;
|
||||
NodeItem rotate3d(NodeItem rotation, bool invert = false);
|
||||
template<class T> NodeItem val(const T &data) const;
|
||||
Type type() const;
|
||||
|
||||
|
@ -148,13 +148,18 @@ NodeItem NodeParser::empty() const
|
||||
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();
|
||||
res.node = graph_->getNode(TEXCOORD_NODE_NAME);
|
||||
res.node = graph_->getNode(name);
|
||||
if (!res.node) {
|
||||
res = create_node("texcoord", NodeItem::Type::Vector2);
|
||||
res.node->setName(TEXCOORD_NODE_NAME);
|
||||
res = create_node("texcoord", type);
|
||||
res.node->setName(name);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ class GroupNodeParser;
|
||||
|
||||
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 {
|
||||
protected:
|
||||
MaterialX::GraphElement *graph_;
|
||||
@ -63,7 +67,7 @@ class NodeParser {
|
||||
NodeItem get_input_value(int index, NodeItem::Type to_type);
|
||||
NodeItem empty() const;
|
||||
template<class T> NodeItem val(const T &data) const;
|
||||
NodeItem texcoord_node();
|
||||
NodeItem texcoord_node(NodeItem::Type type = NodeItem::Type::Vector2);
|
||||
|
||||
private:
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* 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 {
|
||||
MaterialX::GraphElement *graph;
|
||||
|
@ -25,36 +25,23 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem res = empty();
|
||||
switch (to_type_) {
|
||||
case NodeItem::Type::BSDF:
|
||||
case NodeItem::Type::EDF: {
|
||||
if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
NodeItem shader1 = get_input_link(0, to_type_);
|
||||
NodeItem shader2 = get_input_link(1, to_type_);
|
||||
if (!shader1 && !shader2) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
if (shader1 && !shader2) {
|
||||
res = shader1;
|
||||
return shader1;
|
||||
}
|
||||
else if (!shader1 && shader2) {
|
||||
res = shader2;
|
||||
if (!shader1 && shader2) {
|
||||
return 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;
|
||||
return shader1 + shader2;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
@ -289,9 +289,11 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
using InputsType = std::map<std::string, NodeItem>;
|
||||
|
||||
/* NOTE: commented inputs aren't used for node creation. */
|
||||
auto bsdf_inputs = [&]() {
|
||||
return std::map<std::string, NodeItem>{
|
||||
auto bsdf_inputs = [&]() -> InputsType {
|
||||
return {
|
||||
{"base_color", get_input_value("Base Color", NodeItem::Type::Color3)},
|
||||
{"subsurface", get_input_value("Subsurface", NodeItem::Type::Float)},
|
||||
{"subsurface_scale", get_input_value("Subsurface Scale", NodeItem::Type::Float)},
|
||||
@ -320,19 +322,22 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
};
|
||||
};
|
||||
|
||||
auto edf_inputs = [&]() {
|
||||
return std::map<std::string, NodeItem>{
|
||||
auto edf_inputs = [&]() -> InputsType {
|
||||
return {
|
||||
{"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();
|
||||
if (to_type_ == NodeItem::Type::BSDF) {
|
||||
|
||||
switch (to_type_) {
|
||||
case NodeItem::Type::BSDF: {
|
||||
auto in = bsdf_inputs();
|
||||
|
||||
NodeItem roughness = in["roughness"];
|
||||
NodeItem anisotropy = in["anisotropic"];
|
||||
NodeItem rotation = in["anisotropic_rotation"];
|
||||
NodeItem rotation = in["anisotropic_rotation"] * val(360.0f);
|
||||
NodeItem base_color = in["base_color"];
|
||||
NodeItem specular = in["specular"];
|
||||
NodeItem coat = in["coat"];
|
||||
@ -343,14 +348,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
|
||||
NodeItem n_main_tangent = empty();
|
||||
if (tangent && normal) {
|
||||
NodeItem n_tangent_rotate = create_node(
|
||||
"rotate3d",
|
||||
NodeItem::Type::Vector3,
|
||||
{{"in", tangent}, {"amount", rotation * val(360.0f)}, {"axis", normal}});
|
||||
|
||||
NodeItem n_tangent_rotate_normalize = create_node(
|
||||
"normalize", NodeItem::Type::Vector3, {{"in", n_tangent_rotate}});
|
||||
|
||||
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);
|
||||
}
|
||||
@ -370,14 +368,8 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{"normal", coat_normal}});
|
||||
|
||||
if (tangent && coat_normal) {
|
||||
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(
|
||||
"normalize", NodeItem::Type::Vector3, {{"in", n_coat_tangent_rotate}});
|
||||
|
||||
NodeItem n_coat_tangent_rotate_normalize =
|
||||
tangent.rotate(rotation, coat_normal).normalize();
|
||||
NodeItem n_coat_tangent = anisotropy.if_else(
|
||||
NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent);
|
||||
|
||||
@ -396,10 +388,8 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
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_coat_affected_roughness = n_coat_affect_roughness_multiply2.mix(roughness,
|
||||
val(1.0f));
|
||||
|
||||
NodeItem n_main_roughness = create_node(
|
||||
"roughness_anisotropy",
|
||||
@ -424,12 +414,8 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{"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_coat_affected_transmission_roughness = n_coat_affect_roughness_multiply2.mix(
|
||||
(roughness + roughness).clamp(), val(1.0f));
|
||||
|
||||
NodeItem n_transmission_roughness = create_node(
|
||||
"roughness_anisotropy",
|
||||
@ -459,11 +445,6 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{"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"]},
|
||||
@ -478,26 +459,17 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{"weight", val(1.0f)},
|
||||
{"normal", normal}});
|
||||
|
||||
NodeItem n_subsurface_mix = create_node(
|
||||
"mix",
|
||||
NodeItem::Type::BSDF,
|
||||
{{"fg", n_selected_subsurface_bsdf}, {"bg", n_diffuse_bsdf}, {"mix", in["subsurface"]}});
|
||||
NodeItem n_subsurface_mix = in["subsurface"].mix(n_diffuse_bsdf, n_subsurface_bsdf);
|
||||
|
||||
NodeItem n_sheen_layer = create_node(
|
||||
"layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}});
|
||||
|
||||
NodeItem n_transmission_mix = create_node(
|
||||
"mix",
|
||||
NodeItem::Type::BSDF,
|
||||
{{"fg", n_transmission_bsdf}, {"bg", n_sheen_layer}, {"mix", in["transmission"]}});
|
||||
NodeItem n_transmission_mix = in["transmission"].mix(n_sheen_layer, n_transmission_bsdf);
|
||||
|
||||
NodeItem n_specular_layer = create_node(
|
||||
"layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}});
|
||||
|
||||
NodeItem n_metalness_mix = create_node(
|
||||
"mix",
|
||||
NodeItem::Type::BSDF,
|
||||
{{"fg", n_metal_bsdf}, {"bg", n_specular_layer}, {"mix", in["metallic"]}});
|
||||
NodeItem n_metalness_mix = in["metallic"].mix(n_specular_layer, n_metal_bsdf);
|
||||
|
||||
NodeItem n_thin_film_layer = create_node(
|
||||
"layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}});
|
||||
@ -505,23 +477,23 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
NodeItem n_opacity_luminance = create_node(
|
||||
"luminance", NodeItem::Type::Color3, {{"in", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))}});
|
||||
|
||||
NodeItem n_coat_attenuation = create_node("mix",
|
||||
NodeItem::Type::Color3,
|
||||
{{"fg", in["coat_tint"]},
|
||||
{"bg", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))},
|
||||
{"mix", coat}});
|
||||
NodeItem n_coat_attenuation = coat.mix(val(MaterialX::Color3(1.0f, 1.0f, 1.0f)),
|
||||
in["coat_tint"]);
|
||||
|
||||
res = create_node("layer",
|
||||
NodeItem::Type::BSDF,
|
||||
{{"top", n_coat_bsdf}, {"base", n_thin_film_layer * n_coat_attenuation}});
|
||||
break;
|
||||
}
|
||||
else if (to_type_ == NodeItem::Type::EDF) {
|
||||
auto in = edf_inputs();
|
||||
|
||||
case NodeItem::Type::EDF: {
|
||||
auto in = edf_inputs();
|
||||
res = create_node(
|
||||
"uniform_edf", NodeItem::Type::EDF, {{"color", in["emission_color"] * in["emission"]}});
|
||||
break;
|
||||
}
|
||||
else if (to_type_ == NodeItem::Type::SurfaceShader) {
|
||||
|
||||
case NodeItem::Type::SurfaceShader: {
|
||||
auto in = bsdf_inputs();
|
||||
auto e_in = edf_inputs();
|
||||
in.insert(e_in.begin(), e_in.end());
|
||||
@ -564,11 +536,11 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{"emission_color", in["emission_color"]},
|
||||
{"normal", in["normal"]},
|
||||
{"tangent", in["tangent"]}});
|
||||
break;
|
||||
}
|
||||
else {
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@ static int node_shader_gpu_gamma(GPUMaterial *mat,
|
||||
{
|
||||
return GPU_stack_link(mat, node, "node_gamma", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
|
||||
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
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
@ -77,37 +77,31 @@ static void node_shader_update_mapping(bNodeTree *ntree, bNode *node)
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem res = empty();
|
||||
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
||||
|
||||
if (!vector) {
|
||||
return res;
|
||||
}
|
||||
|
||||
NodeItem vector = get_input_value("Vector", 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) *
|
||||
val(float(180.0f / M_PI)));
|
||||
NodeItem rotation = get_input_value("Rotation", NodeItem::Type::Vector3) *
|
||||
val(float(180.0f / M_PI));
|
||||
|
||||
switch (node_->custom1) {
|
||||
case NODE_MAPPING_TYPE_POINT:
|
||||
res = (vector * scale).rotate3d(rotation) + location;
|
||||
break;
|
||||
case NODE_MAPPING_TYPE_TEXTURE:
|
||||
res = (vector - location).rotate3d(rotation, true) / scale;
|
||||
break;
|
||||
case NODE_MAPPING_TYPE_VECTOR:
|
||||
res = (vector * scale).rotate3d(rotation * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f)));
|
||||
break;
|
||||
case NODE_MAPPING_TYPE_NORMAL:
|
||||
res = create_node(
|
||||
"normalize", NodeItem::Type::Vector3, {{"in", (vector / scale).rotate3d(rotation)}});
|
||||
break;
|
||||
int type = node_->custom1;
|
||||
switch (type) {
|
||||
case NODE_MAPPING_TYPE_POINT: {
|
||||
NodeItem location = get_input_value("Location", NodeItem::Type::Vector3);
|
||||
return (vector * scale).rotate(rotation) + location;
|
||||
}
|
||||
case NODE_MAPPING_TYPE_TEXTURE: {
|
||||
NodeItem location = get_input_value("Location", NodeItem::Type::Vector3);
|
||||
return (vector - location).rotate(rotation, true) / scale;
|
||||
}
|
||||
case NODE_MAPPING_TYPE_VECTOR: {
|
||||
return (vector * scale).rotate(rotation * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f)));
|
||||
}
|
||||
case NODE_MAPPING_TYPE_NORMAL: {
|
||||
return (vector / scale).rotate(rotation).normalize();
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
return res;
|
||||
return empty();
|
||||
}
|
||||
#endif
|
||||
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
|
||||
|
||||
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.labelfunc = file_ns::sh_node_mix_label;
|
||||
ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* TODO: Implement */
|
||||
return empty();
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_mix_rgb_cc
|
||||
|
||||
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.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -26,37 +26,25 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem res = empty();
|
||||
switch (to_type_) {
|
||||
case NodeItem::Type::BSDF:
|
||||
case NodeItem::Type::EDF: {
|
||||
NodeItem fac = get_input_value(0, NodeItem::Type::Float);
|
||||
if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
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) {
|
||||
res = shader1 * (val(1.0f) - fac);
|
||||
return shader1 * (val(1.0f) - fac);
|
||||
}
|
||||
else if (!shader1 && shader2) {
|
||||
res = shader2 * fac;
|
||||
if (!shader1 && shader2) {
|
||||
return 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;
|
||||
return fac.mix(shader1, shader2);
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
@ -46,9 +46,10 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem surface = get_input_link("Surface", NodeItem::Type::SurfaceShader);
|
||||
if (!surface) {
|
||||
NodeItem bsdf = get_input_link("Surface", NodeItem::Type::BSDF);
|
||||
NodeItem edf = get_input_link("Surface", NodeItem::Type::EDF);
|
||||
NodeItem surface = empty();
|
||||
if (bsdf || edf) {
|
||||
surface = create_node("surface", NodeItem::Type::SurfaceShader);
|
||||
if (bsdf) {
|
||||
@ -58,8 +59,6 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
surface.set_input("edf", edf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
surface = get_input_link("Surface", NodeItem::Type::SurfaceShader);
|
||||
}
|
||||
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;
|
||||
return convert.extract(index);
|
||||
return convert[index];
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
@ -95,7 +95,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3);
|
||||
int index = STREQ(socket_out_->name, "X") ? 0 : STREQ(socket_out_->name, "Y") ? 1 : 2;
|
||||
return vector.extract(index);
|
||||
return vector[index];
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
@ -118,7 +118,7 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
@ -160,21 +160,21 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
|
||||
switch (gradient_type) {
|
||||
case SHD_BLEND_LINEAR:
|
||||
res = vector.extract(0);
|
||||
res = vector[0];
|
||||
break;
|
||||
case SHD_BLEND_QUADRATIC:
|
||||
res = vector.extract(0);
|
||||
res = vector[0];
|
||||
res = res * res;
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
case SHD_BLEND_DIAGONAL:
|
||||
res = (vector.extract(0) + vector.extract(1)) * val(0.5f);
|
||||
res = (vector[0] + vector[1]) * val(0.5f);
|
||||
break;
|
||||
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;
|
||||
case SHD_BLEND_QUADRATIC_SPHERE:
|
||||
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")) {
|
||||
res = res.extract(3);
|
||||
res = res[3];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -223,59 +223,59 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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 distortion = get_input_value("Distortion", NodeItem::Type::Float) /
|
||||
val(10.0f); // noise adjusment to get result as Cycles
|
||||
NodeItem detail = get_input_value("Detail", 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 distortion = get_input_value("Distortion", NodeItem::Type::Float);
|
||||
NodeItem detail = get_input_default("Detail", NodeItem::Type::Float);
|
||||
NodeItem detail_scale = get_input_value("Detail Scale", 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 vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
||||
if (!vector) {
|
||||
vector = texcoord_node();
|
||||
vector = texcoord_node(NodeItem::Type::Vector3);
|
||||
}
|
||||
|
||||
NodeItem p = vector * scale;
|
||||
p = (p + val(0.000001f)) * val(0.999999f);
|
||||
NodeItem n = val(0.0f);
|
||||
NodeItem value = val(0.0f);
|
||||
/* adjusment to get result as Cycles */
|
||||
distortion = distortion * val(10.0f);
|
||||
detail_scale = detail_scale * val(10.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:
|
||||
switch (bands_direction) {
|
||||
switch (tex->bands_direction) {
|
||||
case SHD_WAVE_BANDS_DIRECTION_X:
|
||||
n = p.extract(0) * val(20.0f);
|
||||
value = pos[0] * val(20.0f);
|
||||
break;
|
||||
case SHD_WAVE_BANDS_DIRECTION_Y:
|
||||
n = p.extract(1) * val(20.0f);
|
||||
value = pos[1] * val(20.0f);
|
||||
break;
|
||||
case SHD_WAVE_BANDS_DIRECTION_Z:
|
||||
n = p.extract(2) * val(20.0f);
|
||||
value = pos[2] * val(20.0f);
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
break;
|
||||
case SHD_WAVE_RINGS:
|
||||
NodeItem rp = p;
|
||||
switch (rings_direction) {
|
||||
NodeItem rpos = pos;
|
||||
switch (tex->rings_direction) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case SHD_WAVE_RINGS_DIRECTION_SPHERICAL:
|
||||
/* Ignore. */
|
||||
@ -283,33 +283,28 @@ NODE_SHADER_MATERIALX_BEGIN
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
n = rp.dotproduct(rp).sqrt() * val(20.0f);
|
||||
value = rpos.length() * val(20.0f);
|
||||
break;
|
||||
}
|
||||
n = n + phase_offset;
|
||||
n = n + distortion * detail_scale *
|
||||
create_node("fractal3d",
|
||||
NodeItem::Type::Float,
|
||||
{{"position", p},
|
||||
{"octaves", val(int(detail.value->asA<float>()))},
|
||||
{"lacunarity", val(2.0f)}});
|
||||
value = value + phase_offset + distortion * detail_scale * fractal;
|
||||
|
||||
switch (wave_profile) {
|
||||
NodeItem res = empty();
|
||||
switch (tex->wave_profile) {
|
||||
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;
|
||||
case SHD_WAVE_PROFILE_SAW:
|
||||
n = n / val(float(M_PI * 2.0f));
|
||||
value = n - n.floor();
|
||||
value = value / val(float(M_PI * 2.0f));
|
||||
res = value - value.floor();
|
||||
break;
|
||||
case SHD_WAVE_PROFILE_TRI:
|
||||
n = n / val(float(M_PI * 2.0f));
|
||||
value = (n - (n + val(0.5f)).floor()).abs() * val(2.0f);
|
||||
value = value / val(float(M_PI * 2.0f));
|
||||
res = (value - (value + val(0.5f)).floor()).abs() * val(2.0f);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return value;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
@ -215,62 +215,42 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
|
||||
int mode = node_->custom1;
|
||||
bool invert = node_->custom2;
|
||||
|
||||
if (!vector) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
NodeItem angle = empty();
|
||||
NodeItem axis = empty();
|
||||
NodeItem vector = get_input_value("Vector", 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));
|
||||
NodeItem res = vector - center;
|
||||
int mode = node_->custom1;
|
||||
bool invert = node_->custom1;
|
||||
vector = vector - center;
|
||||
|
||||
if (mode == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
|
||||
angle = get_input_value("Rotation", NodeItem::Type::Vector3);
|
||||
angle = angle * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
||||
}
|
||||
else {
|
||||
angle = get_input_value("Angle", NodeItem::Type::Float);
|
||||
NodeItem rotation = get_input_value("Rotation", NodeItem::Type::Vector3) *
|
||||
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f) * 180.0f / M_PI);
|
||||
|
||||
return vector.rotate(invert ? -rotation : rotation, invert) + center;
|
||||
}
|
||||
|
||||
angle = angle * val(float(180.0f / M_PI));
|
||||
angle = invert ? angle * val(-1.0f) : angle;
|
||||
|
||||
NodeItem angle = get_input_value("Angle", NodeItem::Type::Float) * val(float(180.0f / M_PI));
|
||||
NodeItem axis = empty();
|
||||
switch (mode) {
|
||||
case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
|
||||
return res.rotate3d(angle, invert) + center;
|
||||
}
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS: {
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS:
|
||||
axis = get_input_value("Axis", NodeItem::Type::Vector3) *
|
||||
val(MaterialX::Vector3(1.0f, 1.0f, -1.0f));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return vector;
|
||||
}
|
||||
}
|
||||
|
||||
return create_node("rotate3d",
|
||||
NodeItem::Type::Vector3,
|
||||
{{"in", res}, {"amount", angle}, {"axis", axis}}) +
|
||||
center;
|
||||
return vector.rotate(invert ? -angle : angle, axis) + center;
|
||||
}
|
||||
#endif
|
||||
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::...
.