Code improvements + Mix node #30

Merged
Bogdan Nagirniak merged 18 commits from BogdanNagirniak/blender:matx-code-improvements into matx-export-material 2023-09-22 18:23:13 +02:00
8 changed files with 80 additions and 57 deletions
Showing only changes of commit 01d67d34fe - Show all commits

View File

@ -82,7 +82,7 @@ void MaterialData::init()
scene_delegate_->depsgraph, (Material *)id); scene_delegate_->depsgraph, (Material *)id);
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;

View File

@ -184,6 +184,8 @@ NodeItem NodeItem::operator^(const NodeItem &other) const
NodeItem NodeItem::operator[](int index) const NodeItem NodeItem::operator[](int index) const
{ {
BLI_assert(is_arithmetic(type()));
if (value) { if (value) {
float v = 0.0f; float v = 0.0f;
switch (type()) { switch (type()) {
@ -264,6 +266,14 @@ NodeItem NodeItem::length() const
return create_node("magnitude", Type::Float, {{"in", to_vector()}}); 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); });
@ -363,6 +373,34 @@ 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 * val(float(180.0f / M_PI))}, {"axis", axis}});
}
NodeItem NodeItem::rotate(const NodeItem &angle_xyz, bool invert)
{
NodeItem angle = angle_xyz * val(float(180.0f / M_PI));
NodeItem x = angle[0];
NodeItem y = angle[1];
NodeItem z = angle[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 to_vector().arithmetic("sin", [](float a) { return std::sinf(a); }); return to_vector().arithmetic("sin", [](float a) { return std::sinf(a); });
@ -706,23 +744,6 @@ 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) {
@ -882,9 +903,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) {

View File

@ -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,
@ -83,12 +85,15 @@ class NodeItem {
NodeItem floor() const; NodeItem floor() const;
NodeItem ceil() const; NodeItem ceil() const;
NodeItem length() 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 mix(const NodeItem &val1, const NodeItem &val2) 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);
NodeItem rotate(const NodeItem &angle_xyz, bool invert = false);
NodeItem sin() const; NodeItem sin() const;
NodeItem cos() const; NodeItem cos() const;
NodeItem tan() const; NodeItem tan() const;
@ -112,7 +117,6 @@ class NodeItem {
/* 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;

View File

@ -18,6 +18,10 @@ extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
class GroupNodeParser; class GroupNodeParser;
/**
* This is base abstraction class for parsing Blender nodes into MaterialX nodes.
* NodeParser::compute() should be overrides in child classes.
*/
class NodeParser { class NodeParser {
protected: protected:
MaterialX::GraphElement *graph_; MaterialX::GraphElement *graph_;
@ -72,8 +76,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;

View File

@ -348,14 +348,7 @@ NODE_SHADER_MATERIALX_BEGIN
NodeItem n_main_tangent = empty(); NodeItem n_main_tangent = empty();
if (tangent && normal) { if (tangent && normal) {
NodeItem n_tangent_rotate = create_node( NodeItem n_tangent_rotate_normalize = tangent.rotate(rotation, normal).normalize();
"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}});
n_main_tangent = anisotropy.if_else( n_main_tangent = anisotropy.if_else(
NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent); NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent);
} }
@ -375,14 +368,8 @@ NODE_SHADER_MATERIALX_BEGIN
{"normal", coat_normal}}); {"normal", coat_normal}});
if (tangent && coat_normal) { if (tangent && coat_normal) {
NodeItem n_coat_tangent_rotate = create_node( NodeItem n_coat_tangent_rotate_normalize =
"rotate3d", tangent.rotate(rotation, coat_normal).normalize();
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 = anisotropy.if_else( NodeItem n_coat_tangent = anisotropy.if_else(
NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent); NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent);

View File

@ -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
{ {

View File

@ -79,34 +79,30 @@ NODE_SHADER_MATERIALX_BEGIN
{ {
NodeItem res = empty(); NodeItem res = empty();
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3); NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3);
if (!vector) { if (!vector) {
return res; return empty();
} }
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 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)));
switch (node_->custom1) { switch (node_->custom1) {
case NODE_MAPPING_TYPE_POINT: case NODE_MAPPING_TYPE_POINT:
res = (vector * scale).rotate3d(rotation) + location; return (vector * scale).rotate(rotation) + location;
break; break;
case NODE_MAPPING_TYPE_TEXTURE: case NODE_MAPPING_TYPE_TEXTURE:
res = (vector - location).rotate3d(rotation, true) / scale; res = (vector - location).rotate(rotation, true) / scale;
break; break;
case NODE_MAPPING_TYPE_VECTOR: case NODE_MAPPING_TYPE_VECTOR:
res = (vector * scale).rotate3d(rotation * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f))); res = (vector * scale).rotate(rotation * val(MaterialX::Vector3(1.0f, 1.0f, -1.0f)));
break; break;
case NODE_MAPPING_TYPE_NORMAL: case NODE_MAPPING_TYPE_NORMAL:
res = create_node( res = (vector / scale).rotate(rotation).normalize();
"normalize", NodeItem::Type::Vector3, {{"in", (vector / scale).rotate3d(rotation)}});
break; break;
default: default:
BLI_assert_unreachable(); BLI_assert_unreachable();
} }
return res; return res;
} }
#endif #endif

View File

@ -237,12 +237,11 @@ NODE_SHADER_MATERIALX_BEGIN
angle = get_input_value("Angle", NodeItem::Type::Float); angle = get_input_value("Angle", NodeItem::Type::Float);
} }
angle = angle * val(float(180.0f / M_PI));
angle = invert ? angle * val(-1.0f) : angle; angle = invert ? angle * val(-1.0f) : angle;
switch (mode) { switch (mode) {
case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: { case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
return res.rotate3d(angle, invert) + center; return res.rotate(angle, invert) + center;
} }
case NODE_VECTOR_ROTATE_TYPE_AXIS: { case NODE_VECTOR_ROTATE_TYPE_AXIS: {
axis = get_input_value("Axis", NodeItem::Type::Vector3) * axis = get_input_value("Axis", NodeItem::Type::Vector3) *