diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 114ab576101d..9a3b77502fbf 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -147,18 +147,24 @@ set(LIB if(WITH_MATERIALX) list(APPEND SRC materialx/material.cc + materialx/nodes/brightness.cc materialx/nodes/bsdf_principled.cc + materialx/nodes/huesatval.cc materialx/nodes/invert.cc materialx/nodes/math.cc materialx/nodes/mix_rgb.cc materialx/nodes/node_item.cc materialx/nodes/node_parser.cc + materialx/nodes/normal_map.cc materialx/nodes/output_material.cc - materialx/nodes/tex_image.cc - materialx/nodes/tex_environment.cc - materialx/nodes/tex_noise.cc + materialx/nodes/sepcomb_color.cc + materialx/nodes/sepcomb_xyz.cc materialx/nodes/tex_checker.cc - + materialx/nodes/tex_environment.cc + materialx/nodes/tex_image.cc + materialx/nodes/tex_noise.cc + materialx/nodes/vector_math.cc + materialx/material.h materialx/nodes/node_item.h materialx/nodes/node_parser.h diff --git a/source/blender/nodes/shader/materialx/nodes/brightness.cc b/source/blender/nodes/shader/materialx/nodes/brightness.cc new file mode 100644 index 000000000000..026621ea4271 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/brightness.cc @@ -0,0 +1,19 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BrightContrastNodeParser::compute() +{ + NodeItem color = get_input_value("Color"); + NodeItem bright = get_input_value("Bright"); + NodeItem contrast = get_input_value("Contrast"); + + /* This formula was given from OSL shader code in Cycles. */ + return (bright + color * (contrast + value(1.0f)) - contrast * value(0.5f)).max(value(0.0f)); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index a8829ddf92fb..5abd13ddaab6 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -8,8 +8,6 @@ namespace blender::nodes::materialx { NodeItem BSDFPrincipledNodeParser::compute() { - NodeItem zero = value(0.0f); - /* Getting required inputs * Note: if some inputs are not needed they won't be taken */ NodeItem base_color = get_input_value("Base Color"); @@ -23,35 +21,20 @@ NodeItem BSDFPrincipledNodeParser::compute() // NodeItem specular_tint = get_input_value("Specular Tint"); NodeItem roughness = get_input_value("Roughness"); - NodeItem anisotropic = empty(); - NodeItem anisotropic_rotation = empty(); - if (metallic != zero) { - /* TODO: use Specular Tint input */ - anisotropic = get_input_value("Anisotropic"); - if (anisotropic != zero) { - anisotropic_rotation = get_input_value("Anisotropic Rotation"); - // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) - } - } + /* TODO: use Specular Tint input */ + NodeItem anisotropic = get_input_value("Anisotropic"); + NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation"); + // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) NodeItem sheen = get_input_value("Sheen"); - // sheen_tint = empty(); - // if enabled(sheen): - // sheen_tint = get_input_value("Sheen Tint"); + // sheen_tint = get_input_value("Sheen Tint"); NodeItem clearcoat = get_input_value("Clearcoat"); - NodeItem clearcoat_roughness = empty(); - if (clearcoat != zero) { - clearcoat_roughness = get_input_value("Clearcoat Roughness"); - } + NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness"); NodeItem ior = get_input_value("IOR"); NodeItem transmission = get_input_value("Transmission"); - NodeItem transmission_roughness = empty(); - if (transmission != zero) { - transmission_roughness = get_input_value("Transmission Roughness"); - } NodeItem emission = get_input_value("Emission"); NodeItem emission_strength = get_input_value("Emission Strength"); @@ -74,59 +57,40 @@ NodeItem BSDFPrincipledNodeParser::compute() if (tangent) { res.set_input("tangent", tangent); } + res.set_input("metalness", metallic); - if (metallic != zero) { - res.set_input("metalness", metallic); - } + res.set_input("specular", specular); + res.set_input("specular_color", base_color, NodeItem::Type::Color3); + res.set_input("specular_roughness", roughness); + res.set_input("specular_IOR", ior); + res.set_input("specular_anisotropy", anisotropic); + res.set_input("specular_rotation", anisotropic_rotation); - if (specular != zero) { - res.set_input("specular", specular); - res.set_input("specular_color", base_color, NodeItem::Type::Color3); - res.set_input("specular_roughness", roughness); - res.set_input("specular_IOR", ior); - if (anisotropic) { - res.set_input("specular_anisotropy", anisotropic); - if (anisotropic_rotation) { - res.set_input("specular_rotation", anisotropic_rotation); - } - } - } - - if (transmission != zero) { - res.set_input("transmission", transmission); - res.set_input("transmission_color", base_color, NodeItem::Type::Color3); - res.set_input("transmission_extra_roughness", transmission_roughness); - } + res.set_input("transmission", transmission); + res.set_input("transmission_color", base_color, NodeItem::Type::Color3); + res.set_input("transmission_extra_roughness", roughness); res.set_input("subsurface", subsurface); - res.set_input("subsurface_color", subsurface_color); - res.set_input("subsurface_radius", subsurface_radius); - if (anisotropic) { - res.set_input("subsurface_anisotropy", anisotropic); - } + res.set_input("subsurface_color", subsurface_color, NodeItem::Type::Color3); + res.set_input("subsurface_radius", subsurface_radius, NodeItem::Type::Color3); + res.set_input("subsurface_anisotropy", anisotropic); - if (sheen != zero) { - res.set_input("sheen", sheen); - res.set_input("sheen_color", base_color, NodeItem::Type::Color3); - res.set_input("sheen_roughness", roughness); - } + res.set_input("sheen", sheen); + res.set_input("sheen_color", base_color, NodeItem::Type::Color3); + res.set_input("sheen_roughness", roughness); - if (clearcoat != zero) { - res.set_input("coat", clearcoat); - res.set_input("coat_color", base_color, NodeItem::Type::Color3); - res.set_input("coat_roughness", clearcoat_roughness); - res.set_input("coat_IOR", ior); - if (anisotropic) { - res.set_input("coat_anisotropy", anisotropic); - res.set_input("coat_rotation", anisotropic_rotation); - } + res.set_input("coat", clearcoat); + res.set_input("coat_color", base_color, NodeItem::Type::Color3); + res.set_input("coat_roughness", clearcoat_roughness); + res.set_input("coat_IOR", ior); + res.set_input("coat_anisotropy", anisotropic); + res.set_input("coat_rotation", anisotropic_rotation); + if (clearcoat_normal) { res.set_input("coat_normal", clearcoat_normal); } - if (emission != zero) { - res.set_input("emission", emission_strength); - res.set_input("emission_color", emission, NodeItem::Type::Color3); - } + res.set_input("emission", emission_strength); + res.set_input("emission_color", emission, NodeItem::Type::Color3); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/huesatval.cc b/source/blender/nodes/shader/materialx/nodes/huesatval.cc new file mode 100644 index 000000000000..8d3af670a299 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/huesatval.cc @@ -0,0 +1,33 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem HueSatValNodeParser::compute() +{ + /* TODO: implement fac, see do_hue_sat_fac in + * source\blender\nodes\texture\nodes\node_texture_hueSatVal.cc */ + NodeItem hue = get_input_value("Hue"); + NodeItem saturation = get_input_value("Saturation"); + NodeItem val = get_input_value("Value"); + NodeItem fac = get_input_value("Fac"); + NodeItem color = get_input_value("Color"); + + /* Modifier to follow Cycles result */ + hue = hue - value(0.5f); + + NodeItem combine = create_node("combine3", "vector3"); + combine.set_input("in1", hue); + combine.set_input("in2", saturation); + combine.set_input("in3", val); + + NodeItem res = create_node("hsvadjust", "color3"); + res.set_input("in", color, NodeItem::Type::Color3); + res.set_input("amount", combine); + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 5e6df0555fce..1b1801e741cf 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -236,6 +236,15 @@ NodeItem NodeItem::exp() const return arithmetic("exp", [](float a) { return std::expf(a); }); } +NodeItem NodeItem::extract(const int index) const +{ + NodeItem res = empty(); + res.node = graph_->addNode("extract", MaterialX::EMPTY_STRING, "float"); + res.set_input("in", *this); + res.set_input("index", val(index)); + return res; +} + NodeItem NodeItem::convert(Type to_type) const { Type from_type = type(); @@ -247,7 +256,7 @@ NodeItem NodeItem::convert(Type to_type) const } if (to_type == Type::Float) { - /* TODO: Convert to float, should be used */ + return extract(0); } /* Converting types which requires > 1 iteration */ diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 466ce42b954d..6e9e011ad2f2 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -76,6 +76,7 @@ class NodeItem { const NodeItem &other, const NodeItem &if_val, const NodeItem &else_val) const; + NodeItem extract(const int index) const; /* Useful functions */ NodeItem empty() const; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 187590c7332f..f3fa66be0ac5 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -132,14 +132,22 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) break; switch (from_node->typeinfo->type) { + CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser) CASE_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser) + CASE_NODE_TYPE(SH_NODE_COMBINE_COLOR, CombineColorNodeParser) + CASE_NODE_TYPE(SH_NODE_COMBXYZ, CombineXYZNodeParser) + CASE_NODE_TYPE(SH_NODE_HUE_SAT, HueSatValNodeParser) CASE_NODE_TYPE(SH_NODE_INVERT, InvertNodeParser) CASE_NODE_TYPE(SH_NODE_MATH, MathNodeParser) CASE_NODE_TYPE(SH_NODE_MIX_RGB_LEGACY, MixRGBNodeParser) + CASE_NODE_TYPE(SH_NODE_NORMAL_MAP, NormalMapNodeParser) + CASE_NODE_TYPE(SH_NODE_SEPARATE_COLOR, SeparateColorNodeParser) + CASE_NODE_TYPE(SH_NODE_SEPXYZ, SeparateXYZNodeParser) CASE_NODE_TYPE(SH_NODE_TEX_CHECKER, TexCheckerNodeParser) CASE_NODE_TYPE(SH_NODE_TEX_ENVIRONMENT, TexEnvironmentNodeParser) CASE_NODE_TYPE(SH_NODE_TEX_IMAGE, TexImageNodeParser) CASE_NODE_TYPE(SH_NODE_TEX_NOISE, TexNoiseNodeParser) + CASE_NODE_TYPE(SH_NODE_VECTOR_MATH, VectorMathNodeParser) default: CLOG_WARN(LOG_MATERIALX_SHADER, diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index bb9986896d99..ebd9ec05c7d7 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -27,6 +27,7 @@ class NodeParser { const bNode *node, const bNodeSocket *socket_out); virtual ~NodeParser() = default; + virtual NodeItem compute() = 0; protected: @@ -60,13 +61,21 @@ template NodeItem NodeParser::value(const T &data) const NodeItem compute() override; \ }; +DECLARE_PARSER(BrightContrastNodeParser) DECLARE_PARSER(BSDFPrincipledNodeParser) +DECLARE_PARSER(CombineColorNodeParser) +DECLARE_PARSER(CombineXYZNodeParser) +DECLARE_PARSER(HueSatValNodeParser) DECLARE_PARSER(InvertNodeParser) DECLARE_PARSER(MathNodeParser) DECLARE_PARSER(MixRGBNodeParser) +DECLARE_PARSER(NormalMapNodeParser) +DECLARE_PARSER(SeparateColorNodeParser) +DECLARE_PARSER(SeparateXYZNodeParser) DECLARE_PARSER(TexCheckerNodeParser) DECLARE_PARSER(TexEnvironmentNodeParser) DECLARE_PARSER(TexImageNodeParser) DECLARE_PARSER(TexNoiseNodeParser) +DECLARE_PARSER(VectorMathNodeParser) } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/normal_map.cc b/source/blender/nodes/shader/materialx/nodes/normal_map.cc new file mode 100644 index 000000000000..b7cc0ff9a209 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/normal_map.cc @@ -0,0 +1,40 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../material.h" +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem NormalMapNodeParser::compute() +{ + std::string default_space = "object"; + NodeShaderNormalMap *normal_map_node = static_cast(node_->storage); + NodeItem color = get_input_value("Color"); + NodeItem strength = get_input_value("Strength"); + + NodeItem res = create_node("normalmap", "vector3"); + res.set_input("in", color, NodeItem::Type::Color3); + res.set_input("scale", strength); + + switch (normal_map_node->space) { + case SHD_SPACE_TANGENT: + res.set_input("space", value(std::string("tangent"))); + break; + case SHD_SPACE_OBJECT: + res.set_input("space", value(std::string("tangent"))); + break; + default: + res.set_input("space", value(default_space)); + CLOG_WARN(LOG_MATERIALX_SHADER, + "Ignoring unsupported Space: %d %s (%d), %s will be used", + normal_map_node->space, + node_->name, + node_->type, + default_space); + } + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc b/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc new file mode 100644 index 000000000000..02f7d60e1bf9 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc @@ -0,0 +1,72 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../material.h" +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem SeparateColorNodeParser::compute() +{ + int mode = static_cast(node_->storage)->mode; + NodeItem color = get_input_value("Color"); + + NodeItem convert = empty(); + + switch (mode) { + case NODE_COMBSEP_COLOR_RGB: + break; + case NODE_COMBSEP_COLOR_HSV: + convert = create_node("rgbtohsv", "color3"); + convert.set_input("in", color); + break; + case NODE_COMBSEP_COLOR_HSL: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported color model, using HSV instead: %d", mode); + convert = create_node("rgbtohsv", "color3"); + convert.set_input("in", color); + break; + default: + BLI_assert_unreachable(); + } + + int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2; + + NodeItem res = convert ? convert : color; + return res.extract(index); +} + +NodeItem CombineColorNodeParser::compute() +{ + int mode = static_cast(node_->storage)->mode; + NodeItem red = get_input_value("Red"); + NodeItem green = get_input_value("Green"); + NodeItem blue = get_input_value("Blue"); + + NodeItem convert = empty(); + NodeItem combine = create_node("combine3", "color3"); + combine.set_input("in1", red); + combine.set_input("in2", green); + combine.set_input("in3", blue); + + switch (mode) { + case NODE_COMBSEP_COLOR_RGB: + break; + case NODE_COMBSEP_COLOR_HSV: + convert = create_node("hsvtorgb", "color3"); + convert.set_input("in", combine); + break; + case NODE_COMBSEP_COLOR_HSL: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported color model, using HSV instead: %d", mode); + convert = create_node("hsvtorgb", "color3"); + convert.set_input("in", combine); + break; + default: + BLI_assert_unreachable(); + } + + NodeItem res = convert ? convert : combine; + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc b/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc new file mode 100644 index 000000000000..104130d840ba --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc @@ -0,0 +1,28 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem SeparateXYZNodeParser::compute() +{ + NodeItem vector = get_input_value("Vector"); + int index = STREQ(socket_out_->name, "X") ? 0 : STREQ(socket_out_->name, "Y") ? 1 : 2; + return vector.extract(index); +} + +NodeItem CombineXYZNodeParser::compute() +{ + NodeItem x = get_input_value("X"); + NodeItem y = get_input_value("Y"); + NodeItem z = get_input_value("Z"); + NodeItem res = create_node("combine3", "vector3"); + res.set_input("in1", x); + res.set_input("in2", y); + res.set_input("in3", z); + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/vector_math.cc b/source/blender/nodes/shader/materialx/nodes/vector_math.cc new file mode 100644 index 000000000000..db8a165a6269 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/vector_math.cc @@ -0,0 +1,122 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../material.h" +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem VectorMathNodeParser::compute() +{ + /* TODO: finish some math operations */ + auto op = node_->custom1; + NodeItem res = empty(); + + /* Single operand operations */ + NodeItem x = get_input_value(0); + switch (op) { + case NODE_VECTOR_MATH_SINE: + res = x.sin(); + break; + case NODE_VECTOR_MATH_COSINE: + res = x.cos(); + break; + case NODE_VECTOR_MATH_TANGENT: + res = x.tan(); + break; + case NODE_VECTOR_MATH_ABSOLUTE: + res = x.abs(); + break; + case NODE_VECTOR_MATH_FLOOR: + res = x.floor(); + break; + case NODE_VECTOR_MATH_CEIL: + res = x.ceil(); + break; + case NODE_VECTOR_MATH_FRACTION: + res = x % value(1.0f); + break; + case NODE_VECTOR_MATH_LENGTH: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_NORMALIZE: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + + default: { + /* 2-operand operations */ + NodeItem y = get_input_value(1); + switch (op) { + case NODE_VECTOR_MATH_ADD: + res = x + y; + break; + case NODE_VECTOR_MATH_SUBTRACT: + res = x - y; + break; + case NODE_VECTOR_MATH_MULTIPLY: + res = x * y; + break; + case NODE_VECTOR_MATH_DIVIDE: + res = x / y; + break; + case NODE_VECTOR_MATH_MINIMUM: + res = x.min(y); + break; + case NODE_VECTOR_MATH_MAXIMUM: + res = x.max(y); + break; + case NODE_VECTOR_MATH_MODULO: + res = x % y; + break; + case NODE_VECTOR_MATH_SNAP: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_CROSS_PRODUCT: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_DOT_PRODUCT: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_PROJECT: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_REFLECT: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_DISTANCE: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_SCALE: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + + default: { + /* 3-operand operations */ + NodeItem z = get_input_value(2); + switch (op) { + case NODE_VECTOR_MATH_MULTIPLY_ADD: + res = x * y + z; + break; + case NODE_VECTOR_MATH_REFRACT: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_FACEFORWARD: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_VECTOR_MATH_WRAP: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + + default: + BLI_assert_unreachable(); + } + } + } + } + } + + return res; +} + +} // namespace blender::nodes::materialx