From 1c3aa08b55cc777942937bd3221b28ddf0ece0aa Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 17 Aug 2023 16:34:42 +0300 Subject: [PATCH 01/40] MaterialX: added default material export --- source/blender/nodes/shader/CMakeLists.txt | 9 +++++ .../nodes/shader/materialx/material.cc | 38 +++++++++++++++++++ .../blender/nodes/shader/materialx/material.h | 16 ++++++++ 3 files changed, 63 insertions(+) create mode 100644 source/blender/nodes/shader/materialx/material.cc create mode 100644 source/blender/nodes/shader/materialx/material.h diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 5967f15f519..c05bb53c9e1 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -134,6 +134,15 @@ set(LIB bf_nodes ) +if(WITH_MATERIALX) + list(APPEND LIB MaterialXCore) + list(APPEND SRC + materialx/material.cc + + materialx/material.h + ) +endif() + if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc new file mode 100644 index 00000000000..9f8c497743b --- /dev/null +++ b/source/blender/nodes/shader/materialx/material.cc @@ -0,0 +1,38 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "material.h" + +#include + +namespace blender::nodes::materialx { + +static void create_standard_surface(MaterialX::DocumentPtr doc, Material *material) +{ + MaterialX::NodePtr surfacematerial = doc->addNode( + "surfacematerial", MaterialX::EMPTY_STRING, "material"); + MaterialX::NodePtr standard_surface = doc->addNode( + "standard_surface", MaterialX::EMPTY_STRING, "surfaceshader"); + + standard_surface->addInput("base", "float")->setValue(1.0); + standard_surface->addInput("base_color", "color3") + ->setValue(MaterialX::Color3(material->r, material->g, material->a)); + + surfacematerial->addInput(standard_surface->getType(), standard_surface->getType()) + ->setNodeName(standard_surface->getName()); +} + +MaterialX::DocumentPtr export_to_materialx(Material* material) { + MaterialX::DocumentPtr doc = MaterialX::createDocument(); + if (material->use_nodes) { + ; + } + else { + create_standard_surface(doc, material); + } + return doc; +} + +} // namespace blender::materialx + diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h new file mode 100644 index 00000000000..d0706153b67 --- /dev/null +++ b/source/blender/nodes/shader/materialx/material.h @@ -0,0 +1,16 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +#include "DNA_material_types.h" + +namespace blender::nodes::materialx { + +MaterialX::DocumentPtr export_to_materialx(Material *material); + +} // namespace blender::materialx + -- 2.30.2 From b89fb0785ef35f01030fbb00912d070b1eb5778c Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 24 Aug 2023 10:22:40 +0200 Subject: [PATCH 02/40] Add basic supported nodes ### Purpose Add basic supported nodes: `Material output`, `Principled BSDF`, `Image Texture`. ### Technical steps * Added base class `MaterialXNode` for all MatX nodes * Added basic supported nodes: `Material output`, `Principled BSDF`, `Image Texture` * Added function `export_nodegraph` * Fix typo Pull Request: https://projects.blender.org/DagerD/blender/pulls/1 --- source/blender/nodes/shader/CMakeLists.txt | 14 ++ .../nodes/shader/materialx/material.cc | 24 +++- .../blender/nodes/shader/materialx/material.h | 6 +- .../nodes/shader/materialx/nodes/image.cc | 43 ++++++ .../nodes/shader/materialx/nodes/image.h | 24 ++++ .../shader/materialx/nodes/material_output.cc | 35 +++++ .../shader/materialx/nodes/material_output.h | 20 +++ .../nodes/shader/materialx/nodes/node.cc | 17 +++ .../nodes/shader/materialx/nodes/node.h | 33 +++++ .../shader/materialx/nodes/principled_bsdf.cc | 126 ++++++++++++++++++ .../shader/materialx/nodes/principled_bsdf.h | 23 ++++ 11 files changed, 356 insertions(+), 9 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/image.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/image.h create mode 100644 source/blender/nodes/shader/materialx/nodes/material_output.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/material_output.h create mode 100644 source/blender/nodes/shader/materialx/nodes/node.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/node.h create mode 100644 source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/principled_bsdf.h diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index c05bb53c9e1..eeebefeb73a 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -21,6 +21,12 @@ set(INC ${CMAKE_BINARY_DIR}/source/blender/makesrna ) +if(WITH_HYDRA) + list(APPEND INC + ../../io/usd + ) + add_definitions(-DWITH_HYDRA) +endif() set(SRC nodes/node_shader_add_shader.cc @@ -138,8 +144,16 @@ if(WITH_MATERIALX) list(APPEND LIB MaterialXCore) list(APPEND SRC materialx/material.cc + materialx/nodes/node.cc + materialx/nodes/material_output.cc + materialx/nodes/principled_bsdf.cc + materialx/nodes/image.cc materialx/material.h + materialx/nodes/node.h + materialx/nodes/material_output.h + materialx/nodes/principled_bsdf.h + materialx/nodes/image.h ) endif() diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 9f8c497743b..f27be0ac29c 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -3,11 +3,23 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "material.h" +#include "nodes/material_output.h" #include +#include "NOD_shader.h" + namespace blender::nodes::materialx { +static void export_nodegraph(MaterialX::DocumentPtr doc, Depsgraph *depsgraph, Material *material) +{ + material->nodetree->ensure_topology_cache(); + + bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); + MaterialXMaterialOutputNode material_node(doc, depsgraph, material, output_node); + material_node.convert(); +} + static void create_standard_surface(MaterialX::DocumentPtr doc, Material *material) { MaterialX::NodePtr surfacematerial = doc->addNode( @@ -17,16 +29,17 @@ static void create_standard_surface(MaterialX::DocumentPtr doc, Material *materi standard_surface->addInput("base", "float")->setValue(1.0); standard_surface->addInput("base_color", "color3") - ->setValue(MaterialX::Color3(material->r, material->g, material->a)); + ->setValue(MaterialX::Color3(material->r, material->g, material->b)); surfacematerial->addInput(standard_surface->getType(), standard_surface->getType()) - ->setNodeName(standard_surface->getName()); + ->setNodeName(standard_surface->getName()); } -MaterialX::DocumentPtr export_to_materialx(Material* material) { +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material) +{ MaterialX::DocumentPtr doc = MaterialX::createDocument(); if (material->use_nodes) { - ; + export_nodegraph(doc, depsgraph, material); } else { create_standard_surface(doc, material); @@ -34,5 +47,4 @@ MaterialX::DocumentPtr export_to_materialx(Material* material) { return doc; } -} // namespace blender::materialx - +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h index d0706153b67..1784c42349b 100644 --- a/source/blender/nodes/shader/materialx/material.h +++ b/source/blender/nodes/shader/materialx/material.h @@ -6,11 +6,11 @@ #include +#include "DEG_depsgraph.h" #include "DNA_material_types.h" namespace blender::nodes::materialx { -MaterialX::DocumentPtr export_to_materialx(Material *material); - -} // namespace blender::materialx +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/image.cc b/source/blender/nodes/shader/materialx/nodes/image.cc new file mode 100644 index 00000000000..7faf20485e4 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/image.cc @@ -0,0 +1,43 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node.h" +#include "image.h" + +#include "hydra/image.h" + +#include "DEG_depsgraph_query.h" + +namespace blender::nodes::materialx { + +const MaterialX::Color3 MaterialXTexImageNode::texture_error_color_{1.0, 0.0, 1.0}; + +MaterialXTexImageNode::MaterialXTexImageNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node) + : MaterialXNode(doc, depsgraph, material, node) +{ + matx_node = doc->addNode("image", MaterialX::createValidName(node->name), "color3"); +} + +MaterialX::NodePtr MaterialXTexImageNode::convert() +{ + Image *image = (Image *)node->id; + NodeTexImage *tex = static_cast(node->storage); + Scene *scene = DEG_get_input_scene(depsgraph); + Main *bmain = DEG_get_bmain(depsgraph); + std::string image_path; +#ifdef WITH_HYDRA + image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); +#endif + MaterialX::NodePtr uv_node = doc->addNode("texcoord", MaterialX::EMPTY_STRING, "vector2"); + + matx_node->addInput("file", "filename")->setValue(image_path); + matx_node->addInput("texcoord", "vector2")->setNodeName(uv_node->getName()); + + return matx_node; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/image.h b/source/blender/nodes/shader/materialx/nodes/image.h new file mode 100644 index 00000000000..fc83f8b3e4a --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/image.h @@ -0,0 +1,24 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node.h" + +namespace blender::nodes::materialx { + +class MaterialXTexImageNode : public MaterialXNode { + protected: + /* Following Cycles color for wrong Texture nodes. */ + static const MaterialX::Color3 texture_error_color_; + + public: + MaterialXTexImageNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node); + MaterialX::NodePtr convert() override; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/material_output.cc b/source/blender/nodes/shader/materialx/nodes/material_output.cc new file mode 100644 index 00000000000..541e58bd7bd --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/material_output.cc @@ -0,0 +1,35 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "material_output.h" +#include "principled_bsdf.h" + +namespace blender::nodes::materialx { + +MaterialXMaterialOutputNode::MaterialXMaterialOutputNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node) + : MaterialXNode(doc, depsgraph, material, node) +{ + matx_node = doc->addNode("surfacematerial", MaterialX::createValidName(node->name), "material"); +} + +MaterialX::NodePtr MaterialXMaterialOutputNode::convert() +{ + LISTBASE_FOREACH (const bNodeSocket *, sock, &node->inputs) { + if (!sock->link) { + continue; + } + if (STREQ(sock->name, "Surface")) { + const bNode *inode = sock->link->fromnode; + MaterialXPrincipledBSDFNode surface_node(doc, depsgraph, material, inode); + surface_node.convert(); + matx_node->addInput("surfaceshader", "surfaceshader")->setNodeName(inode->name); + } + } + return matx_node; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/material_output.h b/source/blender/nodes/shader/materialx/nodes/material_output.h new file mode 100644 index 00000000000..8ffda3d00d9 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/material_output.h @@ -0,0 +1,20 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node.h" + +namespace blender::nodes::materialx { + +class MaterialXMaterialOutputNode : public MaterialXNode { + public: + MaterialXMaterialOutputNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node); + MaterialX::NodePtr convert() override; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node.cc b/source/blender/nodes/shader/materialx/nodes/node.cc new file mode 100644 index 00000000000..5b6b18ca011 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node.cc @@ -0,0 +1,17 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node.h" + +namespace blender::nodes::materialx { + +MaterialXNode::MaterialXNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node) + : depsgraph(depsgraph), material(material), node(node), doc(doc) +{ +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node.h b/source/blender/nodes/shader/materialx/nodes/node.h new file mode 100644 index 00000000000..3f95c16ae23 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node.h @@ -0,0 +1,33 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +#include "DEG_depsgraph.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" + +namespace blender::nodes::materialx { + +class MaterialXNode { + public: + const Depsgraph *depsgraph = nullptr; + const Material *material = nullptr; + const bNode *node = nullptr; + MaterialX::NodePtr matx_node; + MaterialX::DocumentPtr doc; + + public: + MaterialXNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node); + virtual ~MaterialXNode() = default; + + virtual MaterialX::NodePtr convert() = 0; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc b/source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc new file mode 100644 index 00000000000..c410dc1378d --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc @@ -0,0 +1,126 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "principled_bsdf.h" + +#include + +namespace blender::nodes::materialx { + +const MaterialX::Color3 MaterialXPrincipledBSDFNode::default_white_color_{1.0, 1.0, 1.0}; + +MaterialXPrincipledBSDFNode::MaterialXPrincipledBSDFNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node) + : MaterialXNode(doc, depsgraph, material, node) +{ + matx_node = doc->addNode( + "standard_surface", MaterialX::createValidName(node->name), "surfaceshader"); +} + +MaterialX::NodePtr MaterialXPrincipledBSDFNode::convert() +{ +#pragma region get inputs + const float *base_color = + node->input_by_identifier("Base Color").default_value_typed()->value; + const float subsurface = + node->input_by_identifier("Subsurface").default_value_typed()->value; + + const float *subsurface_radius = node->input_by_identifier("Subsurface Radius") + .default_value_typed() + ->value; + const float *subsurface_color = node->input_by_identifier("Subsurface Color") + .default_value_typed() + ->value; + const float metallic = + node->input_by_identifier("Metallic").default_value_typed()->value; + const float specular = + node->input_by_identifier("Specular").default_value_typed()->value; + const float roughness = + node->input_by_identifier("Roughness").default_value_typed()->value; + const float anisotropic = + node->input_by_identifier("Anisotropic").default_value_typed()->value; + const float anisotropic_rot = node->input_by_identifier("Anisotropic Rotation") + .default_value_typed() + ->value; + const float sheen = + node->input_by_identifier("Sheen").default_value_typed()->value; + const float clearcoat = + node->input_by_identifier("Clearcoat").default_value_typed()->value; + const float clearcoat_roughness = node->input_by_identifier("Clearcoat Roughness") + .default_value_typed() + ->value; + const float IOR = + node->input_by_identifier("IOR").default_value_typed()->value; + const float transmission = node->input_by_identifier("Transmission") + .default_value_typed() + ->value; + const float *emission = + node->input_by_identifier("Emission").default_value_typed()->value; + const float emission_str = node->input_by_identifier("Emission Strength") + .default_value_typed() + ->value; + const float *normal = + node->input_by_identifier("Normal").default_value_typed()->value; + const float *clearcoat_normal = node->input_by_identifier("Clearcoat Normal") + .default_value_typed() + ->value; + const float *tangent = + node->input_by_identifier("Tangent").default_value_typed()->value; +#pragma endregion get inputs + +#pragma region set inputs + matx_node->addInput("base", "float")->setValue(1.0); + matx_node->addInput("base_color", "color3") + ->setValue(MaterialX::Color3(base_color[0], base_color[1], base_color[2])); + matx_node->addInput("diffuse_roughness", "float")->setValue(roughness); + matx_node->addInput("normal", "vector3") + ->setValue(MaterialX::Vector3(normal[0], normal[1], normal[2])); + matx_node->addInput("tangent", "vector3") + ->setValue(MaterialX::Vector3(tangent[0], tangent[1], tangent[2])); + + matx_node->addInput("metalness", "float")->setValue(metallic); + + matx_node->addInput("specular", "float")->setValue(specular); + matx_node->addInput("specular_color", "color3")->setValue(default_white_color_); + matx_node->addInput("specular_roughness", "float")->setValue(roughness); + matx_node->addInput("specular_IOR", "float")->setValue(IOR); + matx_node->addInput("specular_anisotropy", "float")->setValue(anisotropic); + matx_node->addInput("specular_rotation", "float")->setValue(anisotropic_rot); + + matx_node->addInput("transmission", "float")->setValue(transmission); + matx_node->addInput("transmission_color", "color3")->setValue(default_white_color_); + matx_node->addInput("transmission_extra_roughness", "float")->setValue(roughness); + + matx_node->addInput("subsurface", "float")->setValue(subsurface); + matx_node->addInput("subsurface_color", "color3") + ->setValue(MaterialX::Color3(subsurface_color[0], subsurface_color[1], subsurface_color[2])); + matx_node->addInput("subsurface_radius", "color3") + ->setValue( + MaterialX::Color3(subsurface_radius[0], subsurface_radius[1], subsurface_radius[2])); + matx_node->addInput("subsurface_anisotropy", "float")->setValue(anisotropic); + + matx_node->addInput("sheen", "float")->setValue(sheen); + matx_node->addInput("sheen_color", "color3")->setValue(default_white_color_); + matx_node->addInput("sheen_roughness", "float")->setValue(roughness); + + matx_node->addInput("coat", "float")->setValue(clearcoat); + matx_node->addInput("coat_color", "color3")->setValue(default_white_color_); + matx_node->addInput("coat_roughness", "float")->setValue(clearcoat_roughness); + matx_node->addInput("coat_IOR", "float")->setValue(IOR); + matx_node->addInput("coat_anisotropy", "float")->setValue(anisotropic); + matx_node->addInput("coat_rotation", "float")->setValue(anisotropic_rot); + matx_node->addInput("coat_normal", "vector3") + ->setValue( + MaterialX::Vector3(clearcoat_normal[0], clearcoat_normal[1], clearcoat_normal[2])); + + matx_node->addInput("emission", "float")->setValue(emission_str); + matx_node->addInput("emission_color", "color3") + ->setValue(MaterialX::Color3(emission[0], emission[1], emission[2])); +#pragma endregion set inputs + return matx_node; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/principled_bsdf.h b/source/blender/nodes/shader/materialx/nodes/principled_bsdf.h new file mode 100644 index 00000000000..6b699f9ef3d --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/principled_bsdf.h @@ -0,0 +1,23 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node.h" + +namespace blender::nodes::materialx { + +class MaterialXPrincipledBSDFNode : public MaterialXNode { + protected: + static const MaterialX::Color3 default_white_color_; + + public: + MaterialXPrincipledBSDFNode(MaterialX::DocumentPtr doc, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node); + MaterialX::NodePtr convert() override; +}; + +} // namespace blender::nodes::materialx -- 2.30.2 From 6822cfe9484fde05916258f21f54e2e031cd0cd6 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 24 Aug 2023 15:51:33 +0200 Subject: [PATCH 03/40] Add bl_use_materialx property ### Purpose Add `bl_use_materialx` to `RenderEngine`. MaterialX is utilized for exporting materials to Hydra. ### Technical steps Added property `bl_use_materialx` to `RenderEngine`. Co-authored-by: Vasyl-Pidhirskyi Pull Request: https://projects.blender.org/DagerD/blender/pulls/3 --- source/blender/makesrna/intern/rna_render.cc | 5 +++++ source/blender/nodes/shader/materialx/nodes/image.cc | 2 ++ source/blender/render/RE_engine.h | 1 + 3 files changed, 8 insertions(+) diff --git a/source/blender/makesrna/intern/rna_render.cc b/source/blender/makesrna/intern/rna_render.cc index be59c0832f8..75efabbb1a5 100644 --- a/source/blender/makesrna/intern/rna_render.cc +++ b/source/blender/makesrna/intern/rna_render.cc @@ -1007,6 +1007,11 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use Alembic Procedural", "Support loading Alembic data at render time"); + prop = RNA_def_property(srna, "bl_use_materialx", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "type->flag", RE_USE_MATERIALX); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_ui_text(prop, "Use Material", "Use MaterialX for exporting materials to Hydra"); + RNA_define_verify_sdna(true); } diff --git a/source/blender/nodes/shader/materialx/nodes/image.cc b/source/blender/nodes/shader/materialx/nodes/image.cc index 7faf20485e4..f7f192ace40 100644 --- a/source/blender/nodes/shader/materialx/nodes/image.cc +++ b/source/blender/nodes/shader/materialx/nodes/image.cc @@ -29,6 +29,8 @@ MaterialX::NodePtr MaterialXTexImageNode::convert() Scene *scene = DEG_get_input_scene(depsgraph); Main *bmain = DEG_get_bmain(depsgraph); std::string image_path; + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contain + * pretty general code, so could be moved from bf_usd project. */ #ifdef WITH_HYDRA image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); #endif diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h index fde6014b2d8..4d837c0451d 100644 --- a/source/blender/render/RE_engine.h +++ b/source/blender/render/RE_engine.h @@ -55,6 +55,7 @@ enum RenderEngineTypeFlag { RE_USE_CUSTOM_FREESTYLE = (1 << 8), RE_USE_NO_IMAGE_SAVE = (1 << 9), RE_USE_ALEMBIC_PROCEDURAL = (1 << 10), + RE_USE_MATERIALX = (1 << 11), }; /** #RenderEngine.flag */ -- 2.30.2 From c5b48921bf4d4787bdedbe0d12f0f70cf4def675 Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Mon, 28 Aug 2023 12:29:24 +0200 Subject: [PATCH 04/40] Create parsing system that converts supported nodes and ignores unsupported Implemented node export system: created `class NodeParser` and `class NodeItem`. Co-authored-by: Bogdan Nagirniak Pull Request: https://projects.blender.org/DagerD/blender/pulls/2 --- source/blender/io/usd/CMakeLists.txt | 4 + .../io/usd/hydra/hydra_scene_delegate.h | 2 + source/blender/io/usd/hydra/material.cc | 22 ++- source/blender/nodes/shader/CMakeLists.txt | 17 +- .../nodes/shader/materialx/material.cc | 25 ++- .../shader/materialx/nodes/bsdf_principled.cc | 145 ++++++++++++++ .../shader/materialx/nodes/bsdf_principled.h | 17 ++ .../nodes/shader/materialx/nodes/image.cc | 45 ----- .../nodes/shader/materialx/nodes/image.h | 24 --- .../shader/materialx/nodes/material_output.cc | 35 ---- .../shader/materialx/nodes/material_output.h | 20 -- .../nodes/shader/materialx/nodes/node.cc | 17 -- .../nodes/shader/materialx/nodes/node.h | 33 ---- .../shader/materialx/nodes/node_parser.cc | 180 ++++++++++++++++++ .../shader/materialx/nodes/node_parser.h | 70 +++++++ .../shader/materialx/nodes/output_material.cc | 20 ++ .../shader/materialx/nodes/output_material.h | 17 ++ .../shader/materialx/nodes/principled_bsdf.cc | 126 ------------ .../shader/materialx/nodes/principled_bsdf.h | 23 --- .../nodes/shader/materialx/nodes/tex_image.cc | 34 ++++ .../nodes/shader/materialx/nodes/tex_image.h | 17 ++ source/blender/render/hydra/engine.cc | 1 + 22 files changed, 550 insertions(+), 344 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_principled.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/image.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/image.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/material_output.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/material_output.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/node.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/node.h create mode 100644 source/blender/nodes/shader/materialx/nodes/node_parser.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/node_parser.h create mode 100644 source/blender/nodes/shader/materialx/nodes/output_material.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/output_material.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/principled_bsdf.h create mode 100644 source/blender/nodes/shader/materialx/nodes/tex_image.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/tex_image.h diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 0806cd35510..d913410f834 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -209,6 +209,10 @@ if(WITH_OPENVDB) ) endif() +if(WITH_MATERIALX) + list(APPEND LIB MaterialXCore) +endif() + blender_add_lib(bf_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # RNA_prototypes.h diff --git a/source/blender/io/usd/hydra/hydra_scene_delegate.h b/source/blender/io/usd/hydra/hydra_scene_delegate.h index 157db1e9ab7..424fd7aba79 100644 --- a/source/blender/io/usd/hydra/hydra_scene_delegate.h +++ b/source/blender/io/usd/hydra/hydra_scene_delegate.h @@ -52,7 +52,9 @@ class HydraSceneDelegate : public pxr::HdSceneDelegate { const View3D *view3d = nullptr; Main *bmain = nullptr; Scene *scene = nullptr; + ShadingSettings shading_settings; + bool use_materialx = true; private: ObjectDataMap objects_; diff --git a/source/blender/io/usd/hydra/material.cc b/source/blender/io/usd/hydra/material.cc index fa2c698146b..dca349b2b00 100644 --- a/source/blender/io/usd/hydra/material.cc +++ b/source/blender/io/usd/hydra/material.cc @@ -12,6 +12,9 @@ #include #include +#include +#include + #include "MEM_guardedalloc.h" #include "BKE_lib_id.h" @@ -30,6 +33,7 @@ #include "intern/usd_exporter_context.h" #include "intern/usd_writer_material.h" +#include "shader/materialx/material.h" namespace blender::io::hydra { @@ -66,10 +70,22 @@ void MaterialData::init() time, export_params, image_cache_file_path()}; - /* Create USD material. */ - pxr::UsdShadeMaterial usd_material = usd::create_usd_material( - export_context, material_path, (Material *)id, "st"); + pxr::UsdShadeMaterial usd_material; + if (scene_delegate_->use_materialx) { + MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx( + scene_delegate_->depsgraph, (Material *)id); + pxr::UsdMtlxRead(doc, stage); + if (pxr::UsdPrim materials = stage->GetPrimAtPath(pxr::SdfPath("/MaterialX/Materials"))) { + pxr::UsdPrimSiblingRange children = materials.GetChildren(); + if (!children.empty()) { + usd_material = pxr::UsdShadeMaterial(*children.begin()); + } + } + } + else { + usd_material = usd::create_usd_material(export_context, material_path, (Material *)id, "st"); + } /* Convert USD material to Hydra material network map, adapted for render delegate. */ const pxr::HdRenderDelegate *render_delegate = diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index a1113ec311f..1888021af16 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -145,18 +145,19 @@ set(LIB if(WITH_MATERIALX) list(APPEND LIB MaterialXCore) + list(APPEND LIB MaterialXFormat) list(APPEND SRC materialx/material.cc - materialx/nodes/node.cc - materialx/nodes/material_output.cc - materialx/nodes/principled_bsdf.cc - materialx/nodes/image.cc + materialx/nodes/bsdf_principled.cc + materialx/nodes/node_parser.cc + materialx/nodes/output_material.cc + materialx/nodes/tex_image.cc materialx/material.h - materialx/nodes/node.h - materialx/nodes/material_output.h - materialx/nodes/principled_bsdf.h - materialx/nodes/image.h + materialx/nodes/bsdf_principled.h + materialx/nodes/node_parser.h + materialx/nodes/output_material.h + materialx/nodes/tex_image.h ) endif() diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index f27be0ac29c..8e3350199e8 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -3,34 +3,37 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "material.h" -#include "nodes/material_output.h" +#include "nodes/output_material.h" #include +#include #include "NOD_shader.h" namespace blender::nodes::materialx { -static void export_nodegraph(MaterialX::DocumentPtr doc, Depsgraph *depsgraph, Material *material) +static void export_nodegraph(MaterialX::GraphElement *graph, + Depsgraph *depsgraph, + Material *material) { material->nodetree->ensure_topology_cache(); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); - MaterialXMaterialOutputNode material_node(doc, depsgraph, material, output_node); - material_node.convert(); + OutputMaterialNodeParser parser(graph, depsgraph, material, output_node); + parser.compute(); } -static void create_standard_surface(MaterialX::DocumentPtr doc, Material *material) +static void create_standard_surface(MaterialX::GraphElement *graph, Material *material) { - MaterialX::NodePtr surfacematerial = doc->addNode( - "surfacematerial", MaterialX::EMPTY_STRING, "material"); - MaterialX::NodePtr standard_surface = doc->addNode( + MaterialX::NodePtr standard_surface = graph->addNode( "standard_surface", MaterialX::EMPTY_STRING, "surfaceshader"); standard_surface->addInput("base", "float")->setValue(1.0); standard_surface->addInput("base_color", "color3") ->setValue(MaterialX::Color3(material->r, material->g, material->b)); + MaterialX::NodePtr surfacematerial = graph->addNode( + "surfacematerial", MaterialX::EMPTY_STRING, "material"); surfacematerial->addInput(standard_surface->getType(), standard_surface->getType()) ->setNodeName(standard_surface->getName()); } @@ -39,11 +42,13 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater { MaterialX::DocumentPtr doc = MaterialX::createDocument(); if (material->use_nodes) { - export_nodegraph(doc, depsgraph, material); + export_nodegraph(doc.get(), depsgraph, material); } else { - create_standard_surface(doc, material); + create_standard_surface(doc.get(), material); } + std::string str = MaterialX::writeToXmlString(doc); + printf("\nMaterial: %s\n%s\n", material->id.name, str.c_str()); return doc; } diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc new file mode 100644 index 00000000000..e00bbce4d59 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -0,0 +1,145 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "bsdf_principled.h" + +#include + +namespace blender::nodes::materialx { + +NodeItem BSDFPrincipledNodeParser::compute() +{ + auto enabled = [](NodeItem &val) -> bool { + if (val.node) { + return true; + } + if (!val.value) { + return false; + } + if (val.value->isA()) { + return val.value->asA() != 0.0f; + } + if (val.value->isA()) { + auto c = val.value->asA(); + return c[0] != 0.0f || c[1] != 0.0f || c[2] != 0.0f; + } + return true; + }; + + /* Getting required inputs + * Note: if some inputs are not needed they won't be taken */ + NodeItem base_color = get_input_value("Base Color"); + + NodeItem subsurface = get_input_value("Subsurface"); + NodeItem subsurface_radius = empty_value(); + NodeItem subsurface_color = empty_value(); + if (enabled(subsurface)) { + subsurface_radius = get_input_value("Subsurface Radius"); + subsurface_color = get_input_value("Subsurface Color"); + } + + NodeItem metallic = get_input_value("Metallic"); + NodeItem specular = get_input_value("Specular"); + // NodeItem specular_tint = get_input_value("Specular Tint"); + NodeItem roughness = get_input_value("Roughness"); + + NodeItem anisotropic = empty_value(); + NodeItem anisotropic_rotation = empty_value(); + if (enabled(metallic)) { + /* TODO: use Specular Tint input */ + anisotropic = get_input_value("Anisotropic"); + if (enabled(anisotropic)) { + anisotropic_rotation = get_input_value("Anisotropic Rotation"); + // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) + } + } + + NodeItem sheen = get_input_value("Sheen"); + // sheen_tint = empty_value(); + // if enabled(sheen): + // sheen_tint = get_input_value("Sheen Tint"); + + NodeItem clearcoat = get_input_value("Clearcoat"); + NodeItem clearcoat_roughness = empty_value(); + if (enabled(clearcoat)) { + clearcoat_roughness = get_input_value("Clearcoat Roughness"); + } + + NodeItem ior = get_input_value("IOR"); + + NodeItem transmission = get_input_value("Transmission"); + NodeItem transmission_roughness = empty_value(); + if (enabled(transmission)) { + transmission_roughness = get_input_value("Transmission Roughness"); + } + + NodeItem emission = get_input_value("Emission"); + NodeItem emission_strength = get_input_value("Emission Strength"); + + NodeItem alpha = get_input_value("Alpha"); + // transparency = 1.0 - alpha + + NodeItem normal = get_input_link("Normal"); + NodeItem clearcoat_normal = get_input_link("Clearcoat Normal"); + NodeItem tangent = get_input_link("Tangent"); + + /* Creating standard_surface */ + NodeItem res = create_node("standard_surface", "surfaceshader"); + res.set_input("base", 1.0, "float"); + res.set_input("base_color", base_color.to_color3()); + res.set_input("diffuse_roughness", roughness); + res.set_input("normal", normal); + res.set_input("tangent", tangent); + + if (enabled(metallic)) { + res.set_input("metalness", metallic); + } + + if (enabled(specular)) { + res.set_input("specular", specular); + res.set_input("specular_color", base_color.to_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 (enabled(transmission)) { + res.set_input("transmission", transmission); + res.set_input("transmission_color", base_color.to_color3()); + res.set_input("transmission_extra_roughness", transmission_roughness); + } + + if (enabled(subsurface)) { + res.set_input("subsurface", subsurface); + res.set_input("subsurface_color", subsurface_color); + res.set_input("subsurface_radius", subsurface_radius); + res.set_input("subsurface_anisotropy", anisotropic); + } + + if (enabled(sheen)) { + res.set_input("sheen", sheen); + res.set_input("sheen_color", base_color.to_color3()); + res.set_input("sheen_roughness", roughness); + } + + if (enabled(clearcoat)) { + res.set_input("coat", clearcoat); + res.set_input("coat_color", base_color.to_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); + res.set_input("coat_normal", clearcoat_normal); + } + + if (enabled(emission)) { + res.set_input("emission", emission_strength); + res.set_input("emission_color", emission); + } + + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.h b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.h new file mode 100644 index 00000000000..b4cace6d821 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.h @@ -0,0 +1,17 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +class BSDFPrincipledNodeParser : public NodeParser { + public: + using NodeParser::NodeParser; + NodeItem compute() override; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/image.cc b/source/blender/nodes/shader/materialx/nodes/image.cc deleted file mode 100644 index f7f192ace40..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/image.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node.h" -#include "image.h" - -#include "hydra/image.h" - -#include "DEG_depsgraph_query.h" - -namespace blender::nodes::materialx { - -const MaterialX::Color3 MaterialXTexImageNode::texture_error_color_{1.0, 0.0, 1.0}; - -MaterialXTexImageNode::MaterialXTexImageNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node) - : MaterialXNode(doc, depsgraph, material, node) -{ - matx_node = doc->addNode("image", MaterialX::createValidName(node->name), "color3"); -} - -MaterialX::NodePtr MaterialXTexImageNode::convert() -{ - Image *image = (Image *)node->id; - NodeTexImage *tex = static_cast(node->storage); - Scene *scene = DEG_get_input_scene(depsgraph); - Main *bmain = DEG_get_bmain(depsgraph); - std::string image_path; - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contain - * pretty general code, so could be moved from bf_usd project. */ -#ifdef WITH_HYDRA - image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); -#endif - MaterialX::NodePtr uv_node = doc->addNode("texcoord", MaterialX::EMPTY_STRING, "vector2"); - - matx_node->addInput("file", "filename")->setValue(image_path); - matx_node->addInput("texcoord", "vector2")->setNodeName(uv_node->getName()); - - return matx_node; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/image.h b/source/blender/nodes/shader/materialx/nodes/image.h deleted file mode 100644 index fc83f8b3e4a..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/image.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include "node.h" - -namespace blender::nodes::materialx { - -class MaterialXTexImageNode : public MaterialXNode { - protected: - /* Following Cycles color for wrong Texture nodes. */ - static const MaterialX::Color3 texture_error_color_; - - public: - MaterialXTexImageNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node); - MaterialX::NodePtr convert() override; -}; - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/material_output.cc b/source/blender/nodes/shader/materialx/nodes/material_output.cc deleted file mode 100644 index 541e58bd7bd..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/material_output.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "material_output.h" -#include "principled_bsdf.h" - -namespace blender::nodes::materialx { - -MaterialXMaterialOutputNode::MaterialXMaterialOutputNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node) - : MaterialXNode(doc, depsgraph, material, node) -{ - matx_node = doc->addNode("surfacematerial", MaterialX::createValidName(node->name), "material"); -} - -MaterialX::NodePtr MaterialXMaterialOutputNode::convert() -{ - LISTBASE_FOREACH (const bNodeSocket *, sock, &node->inputs) { - if (!sock->link) { - continue; - } - if (STREQ(sock->name, "Surface")) { - const bNode *inode = sock->link->fromnode; - MaterialXPrincipledBSDFNode surface_node(doc, depsgraph, material, inode); - surface_node.convert(); - matx_node->addInput("surfaceshader", "surfaceshader")->setNodeName(inode->name); - } - } - return matx_node; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/material_output.h b/source/blender/nodes/shader/materialx/nodes/material_output.h deleted file mode 100644 index 8ffda3d00d9..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/material_output.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include "node.h" - -namespace blender::nodes::materialx { - -class MaterialXMaterialOutputNode : public MaterialXNode { - public: - MaterialXMaterialOutputNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node); - MaterialX::NodePtr convert() override; -}; - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node.cc b/source/blender/nodes/shader/materialx/nodes/node.cc deleted file mode 100644 index 5b6b18ca011..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/node.cc +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node.h" - -namespace blender::nodes::materialx { - -MaterialXNode::MaterialXNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node) - : depsgraph(depsgraph), material(material), node(node), doc(doc) -{ -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node.h b/source/blender/nodes/shader/materialx/nodes/node.h deleted file mode 100644 index 3f95c16ae23..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/node.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include - -#include "DEG_depsgraph.h" -#include "DNA_material_types.h" -#include "DNA_node_types.h" - -namespace blender::nodes::materialx { - -class MaterialXNode { - public: - const Depsgraph *depsgraph = nullptr; - const Material *material = nullptr; - const bNode *node = nullptr; - MaterialX::NodePtr matx_node; - MaterialX::DocumentPtr doc; - - public: - MaterialXNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node); - virtual ~MaterialXNode() = default; - - virtual MaterialX::NodePtr convert() = 0; -}; - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc new file mode 100644 index 00000000000..11da5c8158a --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -0,0 +1,180 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +#include "bsdf_principled.h" +#include "tex_image.h" + +#include + +namespace blender::nodes::materialx { + +NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} + +void NodeItem::set_input(const std::string &name, const NodeItem &item) +{ + if (item.value) { + set_input(name, item.value); + } + else if (item.node) { + set_input(name, item.node); + } +} + +void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) +{ + if (value->isA()) { + set_input(name, value->asA(), "float"); + } + else if (value->isA()) { + set_input(name, value->asA(), "vector3"); + } + else if (value->isA()) { + set_input(name, value->asA(), "vector4"); + } + else if (value->isA()) { + set_input(name, value->asA(), "color3"); + } + else if (value->isA()) { + set_input(name, value->asA(), "color4"); + } + else { + BLI_assert_unreachable(); + } +} + +void NodeItem::set_input(const std::string &name, const MaterialX::NodePtr node) +{ + this->node->setConnectedNode(name, node); +} + +NodeItem::operator bool() const +{ + return value || node; +} + +NodeItem NodeItem::to_color3() +{ + NodeItem res(graph_); + if (value) { + if (value->isA()) { + float v = value->asA(); + res.value = MaterialX::Value::createValue(MaterialX::Color3(v, v, v)); + } + else if (value->isA()) { + res.value = value; + } + else if (value->isA()) { + auto c = value->asA(); + res.value = MaterialX::Value::createValue( + MaterialX::Color3(c[0], c[1], c[2])); + } + } + else if (node) { + res.node = node; + } + return res; +} + +NodeParser::NodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node) + : graph(graph), depsgraph(depsgraph), material(material), node(node) +{ +} + +NodeItem NodeParser::create_node(const std::string &mx_category, + const std::string &mx_type, + bool accessory) +{ + NodeItem res = empty_value(); + res.node = graph->addNode(mx_category, + accessory ? MaterialX::EMPTY_STRING : + MaterialX::createValidName(node->name), + mx_type); + return res; +} + +NodeItem NodeParser::get_input_default(const std::string &name) +{ + NodeItem res = empty_value(); + + const bNodeSocket &socket = node->input_by_identifier(name); + switch (socket.type) { + case SOCK_FLOAT: { + float v = socket.default_value_typed()->value; + res.value = MaterialX::Value::createValue(v); + } break; + case SOCK_VECTOR: { + const float *v = socket.default_value_typed()->value; + res.value = MaterialX::Value::createValue( + MaterialX::Vector3(v[0], v[1], v[2])); + } break; + case SOCK_RGBA: { + const float *v = socket.default_value_typed()->value; + res.value = MaterialX::Value::createValue( + MaterialX::Color4(v[0], v[1], v[2], v[3])); + } break; + default: { + // TODO log warn + } + } + return res; +} + +NodeItem NodeParser::get_input_link(const std::string &name) +{ + NodeItem res = empty_value(); + + const bNodeLink *link = node->input_by_identifier(name).link; + if (!(link && link->is_used())) { + return res; + } + + const bNode *in_node = link->fromnode; + + /* Passing NODE_REROUTE nodes */ + while (in_node->type == NODE_REROUTE) { + link = in_node->input_socket(0).link; + if (!(link && link->is_used())) { + return res; + } + in_node = link->fromnode; + } + + /* Getting required NodeParser object */ + std::unique_ptr parser; + switch (in_node->type) { + case SH_NODE_BSDF_PRINCIPLED: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; + case SH_NODE_TEX_IMAGE: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; + default: + // TODO: warning log + return res; + } + + res = parser->compute(); + return res; +} + +NodeItem NodeParser::get_input_value(const std::string &name) +{ + NodeItem res = get_input_link(name); + if (!res) { + res = get_input_default(name); + } + return res; +} + +NodeItem NodeParser::empty_value() +{ + return NodeItem(graph); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h new file mode 100644 index 00000000000..5a021e8bb33 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -0,0 +1,70 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +#include "DEG_depsgraph.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" + +namespace blender::nodes::materialx { + +class NodeItem { + public: + MaterialX::ValuePtr value; + MaterialX::NodePtr node; + + private: + MaterialX::GraphElement *graph_; + + public: + NodeItem(MaterialX::GraphElement *graph); + ~NodeItem() = default; + + template + void set_input(const std::string &name, const T &value, const std::string &mx_type); + void set_input(const std::string &name, const NodeItem &item); + void set_input(const std::string &name, const MaterialX::ValuePtr value); + void set_input(const std::string &name, const MaterialX::NodePtr node); + + operator bool() const; + + NodeItem to_color3(); +}; + +template +void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) +{ + node->setInputValue(name, value, mx_type); +} + +class NodeParser { + public: + MaterialX::GraphElement *graph; + const Depsgraph *depsgraph; + const Material *material; + const bNode *node; + + public: + NodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node); + virtual ~NodeParser() = default; + + virtual NodeItem compute() = 0; + + protected: + NodeItem create_node(const std::string &mx_category, + const std::string &mx_type, + bool accessory = false); + NodeItem get_input_default(const std::string &name); + NodeItem get_input_link(const std::string &name); + NodeItem get_input_value(const std::string &name); + NodeItem empty_value(); +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc new file mode 100644 index 00000000000..6b3a4584ec5 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -0,0 +1,20 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "output_material.h" + +namespace blender::nodes::materialx { + +NodeItem OutputMaterialNodeParser::compute() +{ + NodeItem node = empty_value(); + NodeItem surface = get_input_link("Surface"); + if (surface) { + node = create_node("surfacematerial", "material"); + node.set_input("surfaceshader", surface); + } + return node; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.h b/source/blender/nodes/shader/materialx/nodes/output_material.h new file mode 100644 index 00000000000..0701c0769e8 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/output_material.h @@ -0,0 +1,17 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +class OutputMaterialNodeParser : public NodeParser { + public: + using NodeParser::NodeParser; + NodeItem compute() override; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc b/source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc deleted file mode 100644 index c410dc1378d..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/principled_bsdf.cc +++ /dev/null @@ -1,126 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "principled_bsdf.h" - -#include - -namespace blender::nodes::materialx { - -const MaterialX::Color3 MaterialXPrincipledBSDFNode::default_white_color_{1.0, 1.0, 1.0}; - -MaterialXPrincipledBSDFNode::MaterialXPrincipledBSDFNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node) - : MaterialXNode(doc, depsgraph, material, node) -{ - matx_node = doc->addNode( - "standard_surface", MaterialX::createValidName(node->name), "surfaceshader"); -} - -MaterialX::NodePtr MaterialXPrincipledBSDFNode::convert() -{ -#pragma region get inputs - const float *base_color = - node->input_by_identifier("Base Color").default_value_typed()->value; - const float subsurface = - node->input_by_identifier("Subsurface").default_value_typed()->value; - - const float *subsurface_radius = node->input_by_identifier("Subsurface Radius") - .default_value_typed() - ->value; - const float *subsurface_color = node->input_by_identifier("Subsurface Color") - .default_value_typed() - ->value; - const float metallic = - node->input_by_identifier("Metallic").default_value_typed()->value; - const float specular = - node->input_by_identifier("Specular").default_value_typed()->value; - const float roughness = - node->input_by_identifier("Roughness").default_value_typed()->value; - const float anisotropic = - node->input_by_identifier("Anisotropic").default_value_typed()->value; - const float anisotropic_rot = node->input_by_identifier("Anisotropic Rotation") - .default_value_typed() - ->value; - const float sheen = - node->input_by_identifier("Sheen").default_value_typed()->value; - const float clearcoat = - node->input_by_identifier("Clearcoat").default_value_typed()->value; - const float clearcoat_roughness = node->input_by_identifier("Clearcoat Roughness") - .default_value_typed() - ->value; - const float IOR = - node->input_by_identifier("IOR").default_value_typed()->value; - const float transmission = node->input_by_identifier("Transmission") - .default_value_typed() - ->value; - const float *emission = - node->input_by_identifier("Emission").default_value_typed()->value; - const float emission_str = node->input_by_identifier("Emission Strength") - .default_value_typed() - ->value; - const float *normal = - node->input_by_identifier("Normal").default_value_typed()->value; - const float *clearcoat_normal = node->input_by_identifier("Clearcoat Normal") - .default_value_typed() - ->value; - const float *tangent = - node->input_by_identifier("Tangent").default_value_typed()->value; -#pragma endregion get inputs - -#pragma region set inputs - matx_node->addInput("base", "float")->setValue(1.0); - matx_node->addInput("base_color", "color3") - ->setValue(MaterialX::Color3(base_color[0], base_color[1], base_color[2])); - matx_node->addInput("diffuse_roughness", "float")->setValue(roughness); - matx_node->addInput("normal", "vector3") - ->setValue(MaterialX::Vector3(normal[0], normal[1], normal[2])); - matx_node->addInput("tangent", "vector3") - ->setValue(MaterialX::Vector3(tangent[0], tangent[1], tangent[2])); - - matx_node->addInput("metalness", "float")->setValue(metallic); - - matx_node->addInput("specular", "float")->setValue(specular); - matx_node->addInput("specular_color", "color3")->setValue(default_white_color_); - matx_node->addInput("specular_roughness", "float")->setValue(roughness); - matx_node->addInput("specular_IOR", "float")->setValue(IOR); - matx_node->addInput("specular_anisotropy", "float")->setValue(anisotropic); - matx_node->addInput("specular_rotation", "float")->setValue(anisotropic_rot); - - matx_node->addInput("transmission", "float")->setValue(transmission); - matx_node->addInput("transmission_color", "color3")->setValue(default_white_color_); - matx_node->addInput("transmission_extra_roughness", "float")->setValue(roughness); - - matx_node->addInput("subsurface", "float")->setValue(subsurface); - matx_node->addInput("subsurface_color", "color3") - ->setValue(MaterialX::Color3(subsurface_color[0], subsurface_color[1], subsurface_color[2])); - matx_node->addInput("subsurface_radius", "color3") - ->setValue( - MaterialX::Color3(subsurface_radius[0], subsurface_radius[1], subsurface_radius[2])); - matx_node->addInput("subsurface_anisotropy", "float")->setValue(anisotropic); - - matx_node->addInput("sheen", "float")->setValue(sheen); - matx_node->addInput("sheen_color", "color3")->setValue(default_white_color_); - matx_node->addInput("sheen_roughness", "float")->setValue(roughness); - - matx_node->addInput("coat", "float")->setValue(clearcoat); - matx_node->addInput("coat_color", "color3")->setValue(default_white_color_); - matx_node->addInput("coat_roughness", "float")->setValue(clearcoat_roughness); - matx_node->addInput("coat_IOR", "float")->setValue(IOR); - matx_node->addInput("coat_anisotropy", "float")->setValue(anisotropic); - matx_node->addInput("coat_rotation", "float")->setValue(anisotropic_rot); - matx_node->addInput("coat_normal", "vector3") - ->setValue( - MaterialX::Vector3(clearcoat_normal[0], clearcoat_normal[1], clearcoat_normal[2])); - - matx_node->addInput("emission", "float")->setValue(emission_str); - matx_node->addInput("emission_color", "color3") - ->setValue(MaterialX::Color3(emission[0], emission[1], emission[2])); -#pragma endregion set inputs - return matx_node; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/principled_bsdf.h b/source/blender/nodes/shader/materialx/nodes/principled_bsdf.h deleted file mode 100644 index 6b699f9ef3d..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/principled_bsdf.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include "node.h" - -namespace blender::nodes::materialx { - -class MaterialXPrincipledBSDFNode : public MaterialXNode { - protected: - static const MaterialX::Color3 default_white_color_; - - public: - MaterialXPrincipledBSDFNode(MaterialX::DocumentPtr doc, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node); - MaterialX::NodePtr convert() override; -}; - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc new file mode 100644 index 00000000000..3d1a0423c9f --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -0,0 +1,34 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "tex_image.h" +#include "node_parser.h" + +#include "hydra/image.h" + +#include "DEG_depsgraph_query.h" + +namespace blender::nodes::materialx { + +NodeItem TexImageNodeParser::compute() +{ + Image *image = (Image *)node->id; + NodeTexImage *tex = static_cast(node->storage); + Scene *scene = DEG_get_input_scene(depsgraph); + Main *bmain = DEG_get_bmain(depsgraph); + std::string image_path; + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contain + * pretty general code, so could be moved from bf_usd project. */ +#ifdef WITH_HYDRA + image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); +#endif + + NodeItem texcoord = create_node("texcoord", "vector2", true); + NodeItem res = create_node("image", "color3"); + res.set_input("file", image_path, "filename"); + res.set_input("texcoord", texcoord); + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.h b/source/blender/nodes/shader/materialx/nodes/tex_image.h new file mode 100644 index 00000000000..cc6f962ef88 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.h @@ -0,0 +1,17 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +class TexImageNodeParser : public NodeParser { + public: + using NodeParser::NodeParser; + NodeItem compute() override; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/render/hydra/engine.cc b/source/blender/render/hydra/engine.cc index 82f3c3172d8..5bf5dc653fb 100644 --- a/source/blender/render/hydra/engine.cc +++ b/source/blender/render/hydra/engine.cc @@ -89,6 +89,7 @@ void Engine::sync(Depsgraph *depsgraph, bContext *context) pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"); hydra_scene_delegate_ = std::make_unique(render_index_.get(), scene_path); + hydra_scene_delegate_->use_materialx = bl_engine_->type->flag & RE_USE_MATERIALX; } hydra_scene_delegate_->populate(depsgraph, context ? CTX_wm_view3d(context) : nullptr); } -- 2.30.2 From 2a2c90226f1dc486fb2a940e351438799a360fb4 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 29 Aug 2023 09:25:57 +0200 Subject: [PATCH 05/40] Arithmetic support for NodeItem and node implementation with arithmetic ### Purpose NodeItem requires arithmetic functions for export implementation of blender nodes. ### Technical steps 1. Added basic arithmetic functions to `NodeItem`. 2. Added some math nodes: `InvertNodeParser`, `MathNodeParser`, `MixRGBNodeParser`. 3. Improved parser declaration: added `DECLARE_PARSER` macros. ### Note Only `InvertNodeParser` is implemented. `MathNodeParser`, `MixRGBNodeParser` are in TODOs. Pull Request: https://projects.blender.org/DagerD/blender/pulls/4 --- source/blender/nodes/shader/CMakeLists.txt | 6 +- .../nodes/shader/materialx/material.cc | 2 +- .../shader/materialx/nodes/bsdf_principled.cc | 4 +- .../nodes/{output_material.h => invert.cc} | 13 +- .../materialx/nodes/{tex_image.h => math.cc} | 12 +- .../nodes/{bsdf_principled.h => mix_rgb.cc} | 12 +- .../shader/materialx/nodes/node_parser.cc | 292 ++++++++++++++++-- .../shader/materialx/nodes/node_parser.h | 44 ++- .../shader/materialx/nodes/output_material.cc | 2 +- .../nodes/shader/materialx/nodes/tex_image.cc | 1 - 10 files changed, 339 insertions(+), 49 deletions(-) rename source/blender/nodes/shader/materialx/nodes/{output_material.h => invert.cc} (54%) rename source/blender/nodes/shader/materialx/nodes/{tex_image.h => math.cc} (61%) rename source/blender/nodes/shader/materialx/nodes/{bsdf_principled.h => mix_rgb.cc} (60%) diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 1888021af16..064f203db34 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -149,15 +149,15 @@ if(WITH_MATERIALX) list(APPEND SRC materialx/material.cc materialx/nodes/bsdf_principled.cc + materialx/nodes/invert.cc + materialx/nodes/math.cc + materialx/nodes/mix_rgb.cc materialx/nodes/node_parser.cc materialx/nodes/output_material.cc materialx/nodes/tex_image.cc materialx/material.h - materialx/nodes/bsdf_principled.h materialx/nodes/node_parser.h - materialx/nodes/output_material.h - materialx/nodes/tex_image.h ) endif() diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 8e3350199e8..5fec3563571 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -3,7 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "material.h" -#include "nodes/output_material.h" +#include "nodes/node_parser.h" #include #include diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index e00bbce4d59..5dee4cc40d6 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -2,9 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "bsdf_principled.h" - -#include +#include "node_parser.h" namespace blender::nodes::materialx { diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.h b/source/blender/nodes/shader/materialx/nodes/invert.cc similarity index 54% rename from source/blender/nodes/shader/materialx/nodes/output_material.h rename to source/blender/nodes/shader/materialx/nodes/invert.cc index 0701c0769e8..b6ca706330f 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.h +++ b/source/blender/nodes/shader/materialx/nodes/invert.cc @@ -2,16 +2,15 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma once - #include "node_parser.h" namespace blender::nodes::materialx { -class OutputMaterialNodeParser : public NodeParser { - public: - using NodeParser::NodeParser; - NodeItem compute() override; -}; +NodeItem InvertNodeParser::compute() +{ + NodeItem fac = get_input_value("Fac"); + NodeItem color = get_input_value("Color"); + return fac.blend(color, fac.val(1.0f) - color); +} } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.h b/source/blender/nodes/shader/materialx/nodes/math.cc similarity index 61% rename from source/blender/nodes/shader/materialx/nodes/tex_image.h rename to source/blender/nodes/shader/materialx/nodes/math.cc index cc6f962ef88..3cee80450a6 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.h +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -2,16 +2,14 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma once - #include "node_parser.h" namespace blender::nodes::materialx { -class TexImageNodeParser : public NodeParser { - public: - using NodeParser::NodeParser; - NodeItem compute() override; -}; +NodeItem MathNodeParser::compute() +{ + /* TODO: implement */ + return empty_value(); +} } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.h b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc similarity index 60% rename from source/blender/nodes/shader/materialx/nodes/bsdf_principled.h rename to source/blender/nodes/shader/materialx/nodes/mix_rgb.cc index b4cace6d821..34cfad6891e 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.h +++ b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc @@ -2,16 +2,14 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma once - #include "node_parser.h" namespace blender::nodes::materialx { -class BSDFPrincipledNodeParser : public NodeParser { - public: - using NodeParser::NodeParser; - NodeItem compute() override; -}; +NodeItem MixRGBNodeParser::compute() +{ + /* TODO: implement */ + return empty_value(); +} } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 11da5c8158a..3b65ec9bf3f 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -4,15 +4,17 @@ #include "node_parser.h" -#include "bsdf_principled.h" -#include "tex_image.h" - #include namespace blender::nodes::materialx { NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} +NodeItem NodeItem::empty() const +{ + return NodeItem(graph_); +} + void NodeItem::set_input(const std::string &name, const NodeItem &item) { if (item.value) { @@ -25,20 +27,27 @@ void NodeItem::set_input(const std::string &name, const NodeItem &item) void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) { + std::string mx_type = value->getTypeString(); if (value->isA()) { - set_input(name, value->asA(), "float"); + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); } else if (value->isA()) { - set_input(name, value->asA(), "vector3"); + set_input(name, value->asA(), mx_type); } else if (value->isA()) { - set_input(name, value->asA(), "vector4"); + set_input(name, value->asA(), mx_type); } else if (value->isA()) { - set_input(name, value->asA(), "color3"); + set_input(name, value->asA(), mx_type); } else if (value->isA()) { - set_input(name, value->asA(), "color4"); + set_input(name, value->asA(), mx_type); + } + else if (value->isA()) { + set_input(name, value->asA(), mx_type); } else { BLI_assert_unreachable(); @@ -55,29 +64,267 @@ NodeItem::operator bool() const return value || node; } -NodeItem NodeItem::to_color3() +NodeItem NodeItem::operator+(const NodeItem &other) const { - NodeItem res(graph_); + return arithmetic(other, "add", [](float a, float b) { return a + b; }); +} + +NodeItem NodeItem::operator-(const NodeItem &other) const +{ + return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); +} + +NodeItem NodeItem::operator*(const NodeItem &other) const +{ + return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); +} + +NodeItem NodeItem::operator/(const NodeItem &other) const +{ + return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); +} + +bool NodeItem::operator==(const NodeItem &other) const +{ + if (node && node == other.node) { + return true; + } + /* TODO: implement */ + return false; +} + +NodeItem NodeItem::min(const NodeItem &other) const +{ + return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); +} + +NodeItem NodeItem::max(const NodeItem &other) const +{ + return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); +} + +NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const +{ + return (val(1.0f) - *this) * a + *this * b; +} + +NodeItem NodeItem::to_color3() const +{ + std::string t = type(); + NodeItem res = empty(); if (value) { - if (value->isA()) { + MaterialX::Color3 c; + if (t == "float") { float v = value->asA(); - res.value = MaterialX::Value::createValue(MaterialX::Color3(v, v, v)); + c = {v, v, v}; } - else if (value->isA()) { - res.value = value; + else if (t == "color3") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; } - else if (value->isA()) { - auto c = value->asA(); - res.value = MaterialX::Value::createValue( - MaterialX::Color3(c[0], c[1], c[2])); + else if (t == "color4") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; } + else if (t == "vector3") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "vector4") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else { + return res; + } + res.value = MaterialX::Value::createValue(c); } else if (node) { + if (t != "color3") { + return res; + } res.node = node; } return res; } +bool NodeItem::is_numeric() const +{ + std::string t = type(); + return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4"); +} + +std::string NodeItem::type() const +{ + return value ? value->getTypeString() : node->getType(); +} + +NodeItem NodeItem::arithmetic(const std::string &mx_category, + std::function func) const +{ + if (!is_numeric()) { + return empty(); + } + + std::string t = value ? value->getTypeString() : node->getType(); + NodeItem res(graph_); + if (value) { + if (t == "float") { + float v = value->asA(); + res.value = MaterialX::Value::createValue(func(v)); + } + else if (t == "color3") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + } + else if (t == "color4") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + } + else if (t == "vector2") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); + } + else if (t == "vector3") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + } + else if (t == "vector4") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + } + else { + BLI_assert_unreachable(); + } + } + else { + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.set_input("in", *this); + } + return res; +} + +NodeItem NodeItem::arithmetic(const NodeItem &other, + const std::string &mx_category, + std::function func) const +{ + NodeItem res = empty(); + if (!is_numeric() || !other.is_numeric()) { + return res; + } + + std::string t1 = type(); + std::string t2 = other.type(); + + if (value && other.value) { + std::string t = t1; + auto val1 = value; + auto val2 = other.value; + if (t1 != t2) { + if (t1 == "float") { + val1 = float_to_type(val1->asA(), t2); + t = t2; + } + else if (t2 == "float") { + val2 = float_to_type(val2->asA(), t1); + } + else { + return res; + } + } + + if (t == "float") { + float v1 = val1->asA(); + float v2 = val2->asA(); + res.value = MaterialX::Value::createValue(func(v1, v2)); + } + else if (t == "color3") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + } + else if (t == "color4") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + } + else if (t == "vector2") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1])}); + } + else if (t == "vector3") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + } + else if (t == "vector4") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + } + else { + BLI_assert_unreachable(); + } + } + else { + std::string t = t1; + auto val1 = *this; + auto val2 = other; + if (t1 != t2) { + if (val1.value && t1 == "float") { + val1.value = float_to_type(val1.value->asA(), t2); + t = t2; + } + else if (val2.value && t2 == "float") { + val2.value = float_to_type(val2.value->asA(), t1); + } + else { + return res; + } + } + + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.set_input("in1", val1); + res.set_input("in2", val2); + } + return res; +} + +MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const +{ + if (t == "float") { + return MaterialX::Value::createValue(v); + } + if (t == "color3") { + return MaterialX::Value::createValue({v, v, v}); + } + if (t == "color4") { + return MaterialX::Value::createValue({v, v, v, 1.0f}); + } + if (t == "vector2") { + return MaterialX::Value::createValue({v, v}); + } + if (t == "vector3") { + return MaterialX::Value::createValue({v, v, v}); + } + if (t == "vector4") { + return MaterialX::Value::createValue({v, v, v, 1.0f}); + } + + BLI_assert_unreachable(); + return nullptr; +} + NodeParser::NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, @@ -151,6 +398,15 @@ NodeItem NodeParser::get_input_link(const std::string &name) case SH_NODE_BSDF_PRINCIPLED: parser = std::make_unique(graph, depsgraph, material, in_node); break; + case SH_NODE_INVERT: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; + case SH_NODE_MATH: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; + case SH_NODE_MIX_RGB_LEGACY: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; case SH_NODE_TEX_IMAGE: parser = std::make_unique(graph, depsgraph, material, in_node); break; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 5a021e8bb33..d2604ff265b 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -24,6 +24,9 @@ class NodeItem { NodeItem(MaterialX::GraphElement *graph); ~NodeItem() = default; + NodeItem empty() const; + template NodeItem val(const T &data) const; + template void set_input(const std::string &name, const T &value, const std::string &mx_type); void set_input(const std::string &name, const NodeItem &item); @@ -31,10 +34,35 @@ class NodeItem { void set_input(const std::string &name, const MaterialX::NodePtr node); operator bool() 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; + bool operator==(const NodeItem &other) const; - NodeItem to_color3(); + NodeItem min(const NodeItem &other) const; + NodeItem max(const NodeItem &other) const; + NodeItem blend(const NodeItem &a, const NodeItem &b) const; + + NodeItem to_color3() const; + bool is_numeric() const; + std::string type() const; + + private: + NodeItem arithmetic(const std::string &mx_category, std::function func) const; + NodeItem arithmetic(const NodeItem &other, + const std::string &mx_category, + std::function func) const; + MaterialX::ValuePtr float_to_type(float v, std::string t) const; }; +template NodeItem NodeItem::val(const T &data) const +{ + NodeItem res(graph_); + res.value = MaterialX::Value::createValue(data); + return res; +} + template void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) { @@ -67,4 +95,18 @@ class NodeParser { NodeItem empty_value(); }; +#define DECLARE_PARSER(T) \ + class T : public NodeParser { \ + public: \ + using NodeParser::NodeParser; \ + NodeItem compute() override; \ + }; + +DECLARE_PARSER(BSDFPrincipledNodeParser) +DECLARE_PARSER(InvertNodeParser) +DECLARE_PARSER(MathNodeParser) +DECLARE_PARSER(MixRGBNodeParser) +DECLARE_PARSER(OutputMaterialNodeParser) +DECLARE_PARSER(TexImageNodeParser) + } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index 6b3a4584ec5..dd44f7692ba 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -2,7 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "output_material.h" +#include "node_parser.h" namespace blender::nodes::materialx { diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc index 3d1a0423c9f..6c0239459e0 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -2,7 +2,6 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "tex_image.h" #include "node_parser.h" #include "hydra/image.h" -- 2.30.2 From 6e49ba3d7678e3147725f28b92369e2cc818fd11 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 31 Aug 2023 12:35:33 +0200 Subject: [PATCH 06/40] Implement export of Math node. Continue other arithmetic support for NodeItem ### Purpose Continuing implementation of arithmetic functions for `NodeItem`. Implement Math node. ### Technical steps 1. Separated implementation of `NodeItem` and `NodeParser` to separate files. 2. Added more functions to `NodeItem`. 3. Implemented Blender Math node. ### Notes Some operations from Math node aren't implemented. Probably will be done in separate task. Pull Request: https://projects.blender.org/DagerD/blender/pulls/6 --- source/blender/nodes/shader/CMakeLists.txt | 2 + .../shader/materialx/nodes/bsdf_principled.cc | 55 +- .../nodes/shader/materialx/nodes/math.cc | 160 ++++- .../nodes/shader/materialx/nodes/mix_rgb.cc | 2 +- .../nodes/shader/materialx/nodes/node_item.cc | 599 ++++++++++++++++++ .../nodes/shader/materialx/nodes/node_item.h | 99 +++ .../shader/materialx/nodes/node_parser.cc | 373 ++--------- .../shader/materialx/nodes/node_parser.h | 75 +-- .../shader/materialx/nodes/output_material.cc | 2 +- 9 files changed, 938 insertions(+), 429 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/node_item.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/node_item.h diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 064f203db34..abbe0851ff5 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -152,11 +152,13 @@ if(WITH_MATERIALX) 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/output_material.cc materialx/nodes/tex_image.cc materialx/material.h + materialx/nodes/node_item.h materialx/nodes/node_parser.h ) endif() diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 5dee4cc40d6..3da7211f7dd 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -8,31 +8,16 @@ namespace blender::nodes::materialx { NodeItem BSDFPrincipledNodeParser::compute() { - auto enabled = [](NodeItem &val) -> bool { - if (val.node) { - return true; - } - if (!val.value) { - return false; - } - if (val.value->isA()) { - return val.value->asA() != 0.0f; - } - if (val.value->isA()) { - auto c = val.value->asA(); - return c[0] != 0.0f || c[1] != 0.0f || c[2] != 0.0f; - } - return true; - }; + 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"); NodeItem subsurface = get_input_value("Subsurface"); - NodeItem subsurface_radius = empty_value(); - NodeItem subsurface_color = empty_value(); - if (enabled(subsurface)) { + NodeItem subsurface_radius = empty(); + NodeItem subsurface_color = empty(); + if (subsurface != zero) { subsurface_radius = get_input_value("Subsurface Radius"); subsurface_color = get_input_value("Subsurface Color"); } @@ -42,33 +27,33 @@ NodeItem BSDFPrincipledNodeParser::compute() // NodeItem specular_tint = get_input_value("Specular Tint"); NodeItem roughness = get_input_value("Roughness"); - NodeItem anisotropic = empty_value(); - NodeItem anisotropic_rotation = empty_value(); - if (enabled(metallic)) { + NodeItem anisotropic = empty(); + NodeItem anisotropic_rotation = empty(); + if (metallic != zero) { /* TODO: use Specular Tint input */ anisotropic = get_input_value("Anisotropic"); - if (enabled(anisotropic)) { + if (anisotropic != zero) { anisotropic_rotation = get_input_value("Anisotropic Rotation"); // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) } } NodeItem sheen = get_input_value("Sheen"); - // sheen_tint = empty_value(); + // sheen_tint = empty(); // if enabled(sheen): // sheen_tint = get_input_value("Sheen Tint"); NodeItem clearcoat = get_input_value("Clearcoat"); - NodeItem clearcoat_roughness = empty_value(); - if (enabled(clearcoat)) { + NodeItem clearcoat_roughness = empty(); + if (clearcoat != zero) { clearcoat_roughness = get_input_value("Clearcoat Roughness"); } NodeItem ior = get_input_value("IOR"); NodeItem transmission = get_input_value("Transmission"); - NodeItem transmission_roughness = empty_value(); - if (enabled(transmission)) { + NodeItem transmission_roughness = empty(); + if (transmission != zero) { transmission_roughness = get_input_value("Transmission Roughness"); } @@ -90,11 +75,11 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("normal", normal); res.set_input("tangent", tangent); - if (enabled(metallic)) { + if (metallic != zero) { res.set_input("metalness", metallic); } - if (enabled(specular)) { + if (specular != zero) { res.set_input("specular", specular); res.set_input("specular_color", base_color.to_color3()); res.set_input("specular_roughness", roughness); @@ -103,26 +88,26 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("specular_rotation", anisotropic_rotation); } - if (enabled(transmission)) { + if (transmission != zero) { res.set_input("transmission", transmission); res.set_input("transmission_color", base_color.to_color3()); res.set_input("transmission_extra_roughness", transmission_roughness); } - if (enabled(subsurface)) { + if (subsurface != zero) { res.set_input("subsurface", subsurface); res.set_input("subsurface_color", subsurface_color); res.set_input("subsurface_radius", subsurface_radius); res.set_input("subsurface_anisotropy", anisotropic); } - if (enabled(sheen)) { + if (sheen != zero) { res.set_input("sheen", sheen); res.set_input("sheen_color", base_color.to_color3()); res.set_input("sheen_roughness", roughness); } - if (enabled(clearcoat)) { + if (clearcoat != zero) { res.set_input("coat", clearcoat); res.set_input("coat_color", base_color.to_color3()); res.set_input("coat_roughness", clearcoat_roughness); @@ -132,7 +117,7 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("coat_normal", clearcoat_normal); } - if (enabled(emission)) { + if (emission != zero) { res.set_input("emission", emission_strength); res.set_input("emission_color", emission); } diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index 3cee80450a6..9fce9a7457d 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -8,8 +8,164 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { - /* TODO: implement */ - return empty_value(); + /* TODO: finish some math operations */ + + auto op = node->custom1; + printf("%d\n", int(op)); + + NodeItem res = empty(); + + /* Single operand operations */ + NodeItem x = get_input_value(0); + switch (op) { + case NODE_MATH_SINE: + res = x.sin(); + break; + case NODE_MATH_COSINE: + res = x.cos(); + break; + case NODE_MATH_TANGENT: + res = x.tan(); + break; + case NODE_MATH_ARCSINE: + res = x.asin(); + break; + case NODE_MATH_ARCCOSINE: + res = x.acos(); + break; + case NODE_MATH_ARCTANGENT: + res = x.atan(); + break; + case NODE_MATH_ROUND: + res = (x + value(0.5f)).floor(); + break; + case NODE_MATH_ABSOLUTE: + res = x.abs(); + break; + case NODE_MATH_FLOOR: + res = x.floor(); + break; + case NODE_MATH_CEIL: + res = x.ceil(); + break; + case NODE_MATH_FRACTION: + res = x % value(1.0f); + break; + case NODE_MATH_SQRT: + res = x.sqrt(); + break; + case NODE_MATH_INV_SQRT: + res = value(1.0f) / x.sqrt(); + break; + case NODE_MATH_SIGN: + res = x.sign(); + break; + case NODE_MATH_EXPONENT: + res = x.exp(); + break; + case NODE_MATH_RADIANS: + res = x * value(float(M_PI) / 180.0f); + break; + case NODE_MATH_DEGREES: + res = x * value(180.0f * float(M_1_PI)); + break; + case NODE_MATH_SINH: + res = x.sinh(); + break; + case NODE_MATH_COSH: + res = x.cosh(); + break; + case NODE_MATH_TANH: + res = x.tanh(); + break; + case NODE_MATH_TRUNC: + res = x.sign() * x.abs().floor(); + break; + + default: { + /* 2-operand operations */ + NodeItem y = get_input_value(1); + switch (op) { + case NODE_MATH_ADD: + res = x + y; + break; + case NODE_MATH_SUBTRACT: + res = x - y; + break; + case NODE_MATH_MULTIPLY: + res = x * y; + break; + case NODE_MATH_DIVIDE: + res = x / y; + break; + case NODE_MATH_POWER: + res = x ^ y; + break; + case NODE_MATH_LOGARITHM: + res = x.ln() / y.ln(); + break; + case NODE_MATH_MINIMUM: + res = x.min(y); + break; + case NODE_MATH_MAXIMUM: + res = x.max(y); + break; + case NODE_MATH_LESS_THAN: + res = x.if_else("<", y, value(1.0f), value(0.0f)); + break; + case NODE_MATH_GREATER_THAN: + res = x.if_else(">", y, value(1.0f), value(0.0f)); + break; + case NODE_MATH_MODULO: + res = x % y; + break; + case NODE_MATH_ARCTAN2: + res = x.atan2(y); + break; + case NODE_MATH_SNAP: + // res = ; + break; + case NODE_MATH_PINGPONG: + // res = ; + break; + case NODE_MATH_FLOORED_MODULO: + // res = ; + break; + + default: { + /* 3-operand operations */ + NodeItem z = get_input_value(2); + switch (op) { + case NODE_MATH_WRAP: + // res = ; + break; + case NODE_MATH_COMPARE: + res = z.if_else("<", (x - y).abs(), value(1.0f), value(0.0f)); + break; + case NODE_MATH_MULTIPLY_ADD: + res = x * y + z; + break; + case NODE_MATH_SMOOTH_MIN: + // res = ; + break; + case NODE_MATH_SMOOTH_MAX: + // res = ; + break; + + default: + BLI_assert_unreachable(); + } + } + } + } + } + + bool clamp_output = node->custom2 != 0; + if (clamp_output && res) { + res = res.clamp(); + } + + return res; } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc index 34cfad6891e..c06cf322a0f 100644 --- a/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc +++ b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc @@ -9,7 +9,7 @@ namespace blender::nodes::materialx { NodeItem MixRGBNodeParser::compute() { /* TODO: implement */ - return empty_value(); + return empty(); } } // 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 new file mode 100644 index 00000000000..8a65fe155a2 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -0,0 +1,599 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_item.h" + +#include "BLI_assert.h" +#include "BLI_utildefines.h" + +namespace blender::nodes::materialx { + +NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} + +NodeItem NodeItem::empty() const +{ + return NodeItem(graph_); +} + +void NodeItem::set_input(const std::string &name, const NodeItem &item) +{ + if (item.value) { + set_input(name, item.value); + } + else if (item.node) { + set_input(name, item.node); + } +} + +void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) +{ + std::string mx_type = value->getTypeString(); + if (mx_type == "float") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "integer") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "vector2") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "vector3") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "vector4") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "color3") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "color4") { + set_input(name, value->asA(), mx_type); + } + else if (mx_type == "string") { + set_input(name, value->asA(), mx_type); + } + else { + BLI_assert_unreachable(); + } +} + +void NodeItem::set_input(const std::string &name, const MaterialX::NodePtr node) +{ + this->node->setConnectedNode(name, node); +} + +NodeItem::operator bool() const +{ + return value || node; +} + +NodeItem NodeItem::operator+(const NodeItem &other) const +{ + return arithmetic(other, "add", [](float a, float b) { return a + b; }); +} + +NodeItem NodeItem::operator-(const NodeItem &other) const +{ + return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); +} + +NodeItem NodeItem::operator-() const +{ + return val(0.0f) - *this; +} + +NodeItem NodeItem::operator*(const NodeItem &other) const +{ + return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); +} + +NodeItem NodeItem::operator/(const NodeItem &other) const +{ + return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); +} + +NodeItem NodeItem::operator%(const NodeItem &other) const +{ + return arithmetic( + other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmodf(a, b); }); +} + +NodeItem NodeItem::operator^(const NodeItem &other) const +{ + return arithmetic(other, "power", [](float a, float b) { return std::powf(a, b); }); +} + +bool NodeItem::operator==(const NodeItem &other) const +{ + if (!*this) { + return !other; + } + if (!other) { + return !*this; + } + if (node && node == other.node) { + return true; + } + if ((node && other.value) || (value && other.node)) { + return false; + } + + std::string mx_type; + auto val1 = value; + auto val2 = other.value; + if (!adjust_types(val1, val2, mx_type)) { + return false; + } + if (mx_type == "float") { + return val1->asA() == val2->asA(); + } + if (mx_type == "color3") { + return val1->asA() == val2->asA(); + } + if (mx_type == "color4") { + return val1->asA() == val2->asA(); + } + if (mx_type == "vector2") { + return val1->asA() == val2->asA(); + } + if (mx_type == "vector3") { + return val1->asA() == val2->asA(); + } + if (mx_type == "vector4") { + return val1->asA() == val2->asA(); + } + + return false; +} + +bool NodeItem::operator!=(const NodeItem &other) const +{ + return !(*this == other); +} + +NodeItem NodeItem::abs() const +{ + return arithmetic("absval", [](float a) { return std::fabsf(a); }); +} + +NodeItem NodeItem::floor() const +{ + return arithmetic("floor", [](float a) { return std::floorf(a); }); +} + +NodeItem NodeItem::ceil() const +{ + return arithmetic("ceil", [](float a) { return std::ceilf(a); }); +} + +NodeItem NodeItem::min(const NodeItem &other) const +{ + return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); +} + +NodeItem NodeItem::max(const NodeItem &other) const +{ + return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); +} + +NodeItem NodeItem::dotproduct(const NodeItem &other) const +{ + NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); + if (d.value) { + std::string mx_type = d.type(); + float f = 0.0f; + if (mx_type == "float") { + f = value->asA(); + } + else if (mx_type == "color3") { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + } + else if (mx_type == "color4") { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + } + else if (mx_type == "vector2") { + auto v = value->asA(); + f = v[0] + v[1]; + } + else if (mx_type == "vector3") { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + } + else if (mx_type == "vector4") { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + } + d.value = MaterialX::Value::createValue(f); + } + return d; +} + +NodeItem NodeItem::if_else(const std::string &condition, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const +{ + if (condition == "<") { + return other.if_else(">", *this, else_val, if_val); + } + if (condition == "<=") { + return other.if_else(">=", *this, else_val, if_val); + } + if (condition == "!=") { + return if_else("==", other, else_val, if_val); + } + + NodeItem res = empty(); + if (type() != "float" || other.type() != "float") { + return res; + } + + auto val1 = if_val; + auto val2 = else_val; + std::string mx_type; + if (!adjust_types(val1, val2, mx_type)) { + return res; + } + + std::function func = nullptr; + std::string mx_category; + if (condition == ">") { + mx_category = "ifgreater"; + func = [](float a, float b) { return a > b; }; + } + else if (condition == ">=") { + mx_category = "ifgreatereq"; + func = [](float a, float b) { return a >= b; }; + } + else if (condition == "==") { + mx_category = "ifequal"; + func = [](float a, float b) { return a == b; }; + } + else { + BLI_assert_unreachable(); + } + + if (value && other.value) { + res = func(value->asA(), other.value->asA()) ? val1 : val2; + } + else { + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); + res.set_input("value1", *this); + res.set_input("value2", other); + res.set_input("in1", val1); + res.set_input("in2", val2); + } + + return res; +} + +NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const +{ + return (val(1.0f) - *this) * a + *this * b; +} + +NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const +{ + return min(max_val).max(min_val); +} + +NodeItem NodeItem::clamp(float min_val, float max_val) const +{ + return clamp(val(min_val), val(max_val)); +} + +NodeItem NodeItem::sin() const +{ + return arithmetic("sin", [](float a) { return std::sinf(a); }); +} + +NodeItem NodeItem::cos() const +{ + return arithmetic("cos", [](float a) { return std::cosf(a); }); +} + +NodeItem NodeItem::tan() const +{ + return arithmetic("tan", [](float a) { return std::tanf(a); }); +} + +NodeItem NodeItem::asin() const +{ + return arithmetic("asin", [](float a) { return std::asinf(a); }); +} + +NodeItem NodeItem::acos() const +{ + return arithmetic("acos", [](float a) { return std::acosf(a); }); +} + +NodeItem NodeItem::atan() const +{ + return 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); }); +} + +NodeItem NodeItem::sinh() const +{ + return (exp() - (-*this).exp()) / val(2.0f); +} + +NodeItem NodeItem::cosh() const +{ + return (exp() - (-*this).exp()) / val(2.0f); +} + +NodeItem NodeItem::tanh() const +{ + return sinh() / cosh(); +} + +NodeItem NodeItem::ln() const +{ + return arithmetic("ln", [](float a) { return std::logf(a); }); +} + +NodeItem NodeItem::sqrt() const +{ + return arithmetic("sqrt", [](float a) { return std::sqrtf(a); }); +} + +NodeItem NodeItem::sign() const +{ + return arithmetic("sign", [](float a) { return a < 0.0f ? -1.0f : (a == 0.0f ? 0.0f : 1.0f); }); +} + +NodeItem NodeItem::exp() const +{ + return arithmetic("exp", [](float a) { return std::expf(a); }); +} + +NodeItem NodeItem::to_color3() const +{ + std::string t = type(); + NodeItem res = empty(); + if (value) { + MaterialX::Color3 c; + if (t == "float") { + float v = value->asA(); + c = {v, v, v}; + } + else if (t == "color3") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "color4") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "vector3") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else if (t == "vector4") { + auto v = value->asA(); + c = {v[0], v[1], v[2]}; + } + else { + return res; + } + res.value = MaterialX::Value::createValue(c); + } + else if (node) { + if (t != "color3") { + return res; + } + res.node = node; + } + return res; +} + +bool NodeItem::is_numeric() const +{ + std::string t = type(); + return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4"); +} + +std::string NodeItem::type() const +{ + return value ? value->getTypeString() : node->getType(); +} + +NodeItem NodeItem::arithmetic(const std::string &mx_category, + std::function func) const +{ + if (!is_numeric()) { + return empty(); + } + + std::string t = value ? value->getTypeString() : node->getType(); + NodeItem res(graph_); + if (value) { + if (t == "float") { + float v = value->asA(); + res.value = MaterialX::Value::createValue(func(v)); + } + else if (t == "color3") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + } + else if (t == "color4") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + } + else if (t == "vector2") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); + } + else if (t == "vector3") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + } + else if (t == "vector4") { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + } + else { + BLI_assert_unreachable(); + } + } + else { + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + res.set_input("in", *this); + } + return res; +} + +NodeItem NodeItem::arithmetic(const NodeItem &other, + const std::string &mx_category, + std::function func) const +{ + NodeItem res = empty(); + if (!is_numeric() || !other.is_numeric()) { + return res; + } + + std::string mx_type; + if (value && other.value) { + auto val1 = value; + auto val2 = other.value; + if (!adjust_types(val1, val2, mx_type)) { + return res; + } + + if (mx_type == "float") { + float v1 = val1->asA(); + float v2 = val2->asA(); + res.value = MaterialX::Value::createValue(func(v1, v2)); + } + else if (mx_type == "color3") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + } + else if (mx_type == "color4") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + } + else if (mx_type == "vector2") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1])}); + } + else if (mx_type == "vector3") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + } + else if (mx_type == "vector4") { + auto v1 = val1->asA(); + auto v2 = val2->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + } + else { + BLI_assert_unreachable(); + } + } + else { + auto val1 = *this; + auto val2 = other; + if (!adjust_types(val1, val2, mx_type)) { + return res; + } + + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); + res.set_input("in1", val1); + res.set_input("in2", val2); + } + return res; +} + +MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string mx_type) +{ + if (mx_type == "float") { + return MaterialX::Value::createValue(v); + } + if (mx_type == "color3") { + return MaterialX::Value::createValue({v, v, v}); + } + if (mx_type == "color4") { + return MaterialX::Value::createValue({v, v, v, 1.0f}); + } + if (mx_type == "vector2") { + return MaterialX::Value::createValue({v, v}); + } + if (mx_type == "vector3") { + return MaterialX::Value::createValue({v, v, v}); + } + if (mx_type == "vector4") { + return MaterialX::Value::createValue({v, v, v, 1.0f}); + } + + BLI_assert_unreachable(); + return nullptr; +} + +bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &mx_type) +{ + std::string t1 = val1->getTypeString(); + std::string t2 = val2->getTypeString(); + if (t1 != t2) { + if (t1 == "float") { + val1 = float_to_type(val1->asA(), t2); + mx_type = t2; + } + else if (t2 == "float") { + val2 = float_to_type(val2->asA(), t1); + mx_type = t1; + } + else { + return false; + } + } + else { + mx_type = t1; + } + return true; +} + +bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type) +{ + std::string t1 = val1.type(); + std::string t2 = val2.type(); + if (t1 != t2) { + if (val1.value && t1 == "float") { + val1.value = float_to_type(val1.value->asA(), t2); + mx_type = t2; + } + else if (val2.value && t2 == "float") { + val2.value = float_to_type(val2.value->asA(), t1); + mx_type = t1; + } + else { + return false; + } + } + else { + mx_type = t1; + } + return true; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h new file mode 100644 index 00000000000..26d3f58b02f --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -0,0 +1,99 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +namespace blender::nodes::materialx { + +class NodeItem { + public: + MaterialX::ValuePtr value; + MaterialX::NodePtr node; + + private: + MaterialX::GraphElement *graph_; + + public: + NodeItem(MaterialX::GraphElement *graph); + ~NodeItem() = default; + + NodeItem empty() const; + template NodeItem val(const T &data) const; + + template + void set_input(const std::string &name, const T &value, const std::string &mx_type); + void set_input(const std::string &name, const NodeItem &item); + void set_input(const std::string &name, const MaterialX::ValuePtr value); + void set_input(const std::string &name, const MaterialX::NodePtr node); + + operator bool() const; + NodeItem operator+(const NodeItem &other) const; + NodeItem operator-(const NodeItem &other) const; + NodeItem operator-() 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; + bool operator==(const NodeItem &other) const; + bool operator!=(const NodeItem &other) const; + + NodeItem abs() const; + NodeItem floor() const; + NodeItem ceil() const; + NodeItem min(const NodeItem &other) const; + NodeItem max(const NodeItem &other) const; + NodeItem dotproduct(const NodeItem &other) const; + NodeItem if_else(const std::string &condition, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const; + NodeItem blend(const NodeItem &a, const NodeItem &b) 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 sin() const; + NodeItem cos() const; + NodeItem tan() const; + NodeItem asin() const; + NodeItem acos() const; + NodeItem atan() const; + NodeItem atan2(const NodeItem &other) const; + NodeItem sinh() const; + NodeItem cosh() const; + NodeItem tanh() const; + NodeItem ln() const; + NodeItem sqrt() const; + NodeItem sign() const; + NodeItem exp() const; + + NodeItem to_color3() const; + bool is_numeric() const; + std::string type() const; + + private: + NodeItem arithmetic(const std::string &mx_category, std::function func) const; + NodeItem arithmetic(const NodeItem &other, + const std::string &mx_category, + std::function func) const; + static MaterialX::ValuePtr float_to_type(float v, std::string mx_type); + /* Functions for adjusting values to make equal types */ + static bool adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &mx_type); + static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type); +}; + +template NodeItem NodeItem::val(const T &data) const +{ + NodeItem res(graph_); + res.value = MaterialX::Value::createValue(data); + return res; +} + +template +void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) +{ + node->setInputValue(name, value, mx_type); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 3b65ec9bf3f..61bda4d3262 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -8,323 +8,6 @@ namespace blender::nodes::materialx { -NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} - -NodeItem NodeItem::empty() const -{ - return NodeItem(graph_); -} - -void NodeItem::set_input(const std::string &name, const NodeItem &item) -{ - if (item.value) { - set_input(name, item.value); - } - else if (item.node) { - set_input(name, item.node); - } -} - -void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) -{ - std::string mx_type = value->getTypeString(); - if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else if (value->isA()) { - set_input(name, value->asA(), mx_type); - } - else { - BLI_assert_unreachable(); - } -} - -void NodeItem::set_input(const std::string &name, const MaterialX::NodePtr node) -{ - this->node->setConnectedNode(name, node); -} - -NodeItem::operator bool() const -{ - return value || node; -} - -NodeItem NodeItem::operator+(const NodeItem &other) const -{ - return arithmetic(other, "add", [](float a, float b) { return a + b; }); -} - -NodeItem NodeItem::operator-(const NodeItem &other) const -{ - return arithmetic(other, "subtract", [](float a, float b) { return a - b; }); -} - -NodeItem NodeItem::operator*(const NodeItem &other) const -{ - return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); -} - -NodeItem NodeItem::operator/(const NodeItem &other) const -{ - return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; }); -} - -bool NodeItem::operator==(const NodeItem &other) const -{ - if (node && node == other.node) { - return true; - } - /* TODO: implement */ - return false; -} - -NodeItem NodeItem::min(const NodeItem &other) const -{ - return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); }); -} - -NodeItem NodeItem::max(const NodeItem &other) const -{ - return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); }); -} - -NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const -{ - return (val(1.0f) - *this) * a + *this * b; -} - -NodeItem NodeItem::to_color3() const -{ - std::string t = type(); - NodeItem res = empty(); - if (value) { - MaterialX::Color3 c; - if (t == "float") { - float v = value->asA(); - c = {v, v, v}; - } - else if (t == "color3") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (t == "color4") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (t == "vector3") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (t == "vector4") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else { - return res; - } - res.value = MaterialX::Value::createValue(c); - } - else if (node) { - if (t != "color3") { - return res; - } - res.node = node; - } - return res; -} - -bool NodeItem::is_numeric() const -{ - std::string t = type(); - return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4"); -} - -std::string NodeItem::type() const -{ - return value ? value->getTypeString() : node->getType(); -} - -NodeItem NodeItem::arithmetic(const std::string &mx_category, - std::function func) const -{ - if (!is_numeric()) { - return empty(); - } - - std::string t = value ? value->getTypeString() : node->getType(); - NodeItem res(graph_); - if (value) { - if (t == "float") { - float v = value->asA(); - res.value = MaterialX::Value::createValue(func(v)); - } - else if (t == "color3") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2])}); - } - else if (t == "color4") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); - } - else if (t == "vector2") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); - } - else if (t == "vector3") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2])}); - } - else if (t == "vector4") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); - } - else { - BLI_assert_unreachable(); - } - } - else { - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); - res.set_input("in", *this); - } - return res; -} - -NodeItem NodeItem::arithmetic(const NodeItem &other, - const std::string &mx_category, - std::function func) const -{ - NodeItem res = empty(); - if (!is_numeric() || !other.is_numeric()) { - return res; - } - - std::string t1 = type(); - std::string t2 = other.type(); - - if (value && other.value) { - std::string t = t1; - auto val1 = value; - auto val2 = other.value; - if (t1 != t2) { - if (t1 == "float") { - val1 = float_to_type(val1->asA(), t2); - t = t2; - } - else if (t2 == "float") { - val2 = float_to_type(val2->asA(), t1); - } - else { - return res; - } - } - - if (t == "float") { - float v1 = val1->asA(); - float v2 = val2->asA(); - res.value = MaterialX::Value::createValue(func(v1, v2)); - } - else if (t == "color3") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); - } - else if (t == "color4") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); - } - else if (t == "vector2") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1])}); - } - else if (t == "vector3") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); - } - else if (t == "vector4") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); - } - else { - BLI_assert_unreachable(); - } - } - else { - std::string t = t1; - auto val1 = *this; - auto val2 = other; - if (t1 != t2) { - if (val1.value && t1 == "float") { - val1.value = float_to_type(val1.value->asA(), t2); - t = t2; - } - else if (val2.value && t2 == "float") { - val2.value = float_to_type(val2.value->asA(), t1); - } - else { - return res; - } - } - - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); - res.set_input("in1", val1); - res.set_input("in2", val2); - } - return res; -} - -MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const -{ - if (t == "float") { - return MaterialX::Value::createValue(v); - } - if (t == "color3") { - return MaterialX::Value::createValue({v, v, v}); - } - if (t == "color4") { - return MaterialX::Value::createValue({v, v, v, 1.0f}); - } - if (t == "vector2") { - return MaterialX::Value::createValue({v, v}); - } - if (t == "vector3") { - return MaterialX::Value::createValue({v, v, v}); - } - if (t == "vector4") { - return MaterialX::Value::createValue({v, v, v, 1.0f}); - } - - BLI_assert_unreachable(); - return nullptr; -} - NodeParser::NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, @@ -337,7 +20,7 @@ NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type, bool accessory) { - NodeItem res = empty_value(); + NodeItem res = empty(); res.node = graph->addNode(mx_category, accessory ? MaterialX::EMPTY_STRING : MaterialX::createValidName(node->name), @@ -347,9 +30,42 @@ NodeItem NodeParser::create_node(const std::string &mx_category, NodeItem NodeParser::get_input_default(const std::string &name) { - NodeItem res = empty_value(); + return get_input_default(node->input_by_identifier(name)); +} - const bNodeSocket &socket = node->input_by_identifier(name); +NodeItem NodeParser::get_input_default(int index) +{ + return get_input_default(node->input_socket(index)); +} + +NodeItem NodeParser::get_input_link(const std::string &name) +{ + return get_input_link(node->input_by_identifier(name)); +} + +NodeItem NodeParser::get_input_link(int index) +{ + return get_input_link(node->input_socket(index)); +} + +NodeItem NodeParser::get_input_value(const std::string &name) +{ + return get_input_value(node->input_by_identifier(name)); +} + +NodeItem NodeParser::get_input_value(int index) +{ + return get_input_value(node->input_socket(index)); +} + +NodeItem NodeParser::empty() const +{ + return NodeItem(graph); +} + +NodeItem NodeParser::get_input_default(const bNodeSocket &socket) +{ + NodeItem res = empty(); switch (socket.type) { case SOCK_FLOAT: { float v = socket.default_value_typed()->value; @@ -372,11 +88,11 @@ NodeItem NodeParser::get_input_default(const std::string &name) return res; } -NodeItem NodeParser::get_input_link(const std::string &name) +NodeItem NodeParser::get_input_link(const bNodeSocket &socket) { - NodeItem res = empty_value(); + NodeItem res = empty(); - const bNodeLink *link = node->input_by_identifier(name).link; + const bNodeLink *link = socket.link; if (!(link && link->is_used())) { return res; } @@ -419,18 +135,13 @@ NodeItem NodeParser::get_input_link(const std::string &name) return res; } -NodeItem NodeParser::get_input_value(const std::string &name) +NodeItem NodeParser::get_input_value(const bNodeSocket &socket) { - NodeItem res = get_input_link(name); + NodeItem res = get_input_link(socket); if (!res) { - res = get_input_default(name); + res = get_input_default(socket); } return res; } -NodeItem NodeParser::empty_value() -{ - return NodeItem(graph); -} - } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index d2604ff265b..4849e430bc3 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -4,7 +4,7 @@ #pragma once -#include +#include "node_item.h" #include "DEG_depsgraph.h" #include "DNA_material_types.h" @@ -12,63 +12,6 @@ namespace blender::nodes::materialx { -class NodeItem { - public: - MaterialX::ValuePtr value; - MaterialX::NodePtr node; - - private: - MaterialX::GraphElement *graph_; - - public: - NodeItem(MaterialX::GraphElement *graph); - ~NodeItem() = default; - - NodeItem empty() const; - template NodeItem val(const T &data) const; - - template - void set_input(const std::string &name, const T &value, const std::string &mx_type); - void set_input(const std::string &name, const NodeItem &item); - void set_input(const std::string &name, const MaterialX::ValuePtr value); - void set_input(const std::string &name, const MaterialX::NodePtr node); - - operator bool() 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; - bool operator==(const NodeItem &other) const; - - NodeItem min(const NodeItem &other) const; - NodeItem max(const NodeItem &other) const; - NodeItem blend(const NodeItem &a, const NodeItem &b) const; - - NodeItem to_color3() const; - bool is_numeric() const; - std::string type() const; - - private: - NodeItem arithmetic(const std::string &mx_category, std::function func) const; - NodeItem arithmetic(const NodeItem &other, - const std::string &mx_category, - std::function func) const; - MaterialX::ValuePtr float_to_type(float v, std::string t) const; -}; - -template NodeItem NodeItem::val(const T &data) const -{ - NodeItem res(graph_); - res.value = MaterialX::Value::createValue(data); - return res; -} - -template -void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) -{ - node->setInputValue(name, value, mx_type); -} - class NodeParser { public: MaterialX::GraphElement *graph; @@ -90,11 +33,25 @@ class NodeParser { const std::string &mx_type, bool accessory = false); NodeItem get_input_default(const std::string &name); + NodeItem get_input_default(int index); NodeItem get_input_link(const std::string &name); + NodeItem get_input_link(int index); NodeItem get_input_value(const std::string &name); - NodeItem empty_value(); + NodeItem get_input_value(int index); + NodeItem empty() const; + template NodeItem value(const T &data) const; + + private: + NodeItem get_input_default(const bNodeSocket &socket); + NodeItem get_input_link(const bNodeSocket &socket); + NodeItem get_input_value(const bNodeSocket &socket); }; +template NodeItem NodeParser::value(const T &data) const +{ + return empty().val(data); +} + #define DECLARE_PARSER(T) \ class T : public NodeParser { \ public: \ diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index dd44f7692ba..94a106c40c0 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -8,7 +8,7 @@ namespace blender::nodes::materialx { NodeItem OutputMaterialNodeParser::compute() { - NodeItem node = empty_value(); + NodeItem node = empty(); NodeItem surface = get_input_link("Surface"); if (surface) { node = create_node("surfacematerial", "material"); -- 2.30.2 From 4dfb0c5857a6aed0dca3b046c12591b6d8de632b Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 31 Aug 2023 19:49:15 +0200 Subject: [PATCH 07/40] Export to MatX various Texture nodes ### Purpose Add support for various Texture nodes. ### Technical steps Added support for: * Checker Texture * Noise Texture Extended NodeItem::set_input() by adding output_name. Added NodeItem::add_output() ### Notes Environment Texture. `Projection` property is not supported for now. Co-authored-by: Bogdan Nagirniak Pull Request: https://projects.blender.org/DagerD/blender/pulls/5 --- source/blender/nodes/shader/CMakeLists.txt | 3 ++ .../shader/materialx/nodes/bsdf_principled.cc | 2 +- .../nodes/shader/materialx/nodes/node_item.cc | 22 ++++++-- .../nodes/shader/materialx/nodes/node_item.h | 13 +++-- .../shader/materialx/nodes/node_parser.cc | 17 ++++-- .../shader/materialx/nodes/node_parser.h | 5 +- .../shader/materialx/nodes/output_material.cc | 2 +- .../shader/materialx/nodes/tex_checker.cc | 52 +++++++++++++++++++ .../shader/materialx/nodes/tex_environment.cc | 33 ++++++++++++ .../nodes/shader/materialx/nodes/tex_image.cc | 6 +-- .../nodes/shader/materialx/nodes/tex_noise.cc | 28 ++++++++++ 11 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/tex_checker.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/tex_environment.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/tex_noise.cc diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index abbe0851ff5..991128fec7f 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -156,6 +156,9 @@ if(WITH_MATERIALX) materialx/nodes/node_parser.cc materialx/nodes/output_material.cc materialx/nodes/tex_image.cc + materialx/nodes/tex_environment.cc + materialx/nodes/tex_noise.cc + materialx/nodes/tex_checker.cc materialx/material.h materialx/nodes/node_item.h diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 3da7211f7dd..a87a0782881 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -68,7 +68,7 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem tangent = get_input_link("Tangent"); /* Creating standard_surface */ - NodeItem res = create_node("standard_surface", "surfaceshader"); + NodeItem res = create_node("standard_surface", "surfaceshader", false); res.set_input("base", 1.0, "float"); res.set_input("base_color", base_color.to_color3()); res.set_input("diffuse_roughness", roughness); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 8a65fe155a2..b5b85fb6eea 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -16,13 +16,15 @@ NodeItem NodeItem::empty() const return NodeItem(graph_); } -void NodeItem::set_input(const std::string &name, const NodeItem &item) +void NodeItem::set_input(const std::string &name, + const NodeItem &item, + const std::string &output_name) { if (item.value) { set_input(name, item.value); } else if (item.node) { - set_input(name, item.node); + set_input(name, item.node, output_name); } } @@ -58,9 +60,19 @@ void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr valu } } -void NodeItem::set_input(const std::string &name, const MaterialX::NodePtr node) +void NodeItem::set_input(const std::string &name, + const MaterialX::NodePtr node, + const std::string &output_name) { this->node->setConnectedNode(name, node); + if (output_name != "") { + this->node->setConnectedOutput("in1", node->getOutput(output_name)); + } +} + +void NodeItem::add_output(const std::string &name, const std::string &mx_type) +{ + node->addOutput(name, mx_type); } NodeItem::operator bool() const @@ -550,7 +562,9 @@ MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string mx_type) return nullptr; } -bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &mx_type) +bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, + MaterialX::ValuePtr &val2, + std::string &mx_type) { std::string t1 = val1->getTypeString(); std::string t2 = val2->getTypeString(); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 26d3f58b02f..2f746cda36b 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -25,9 +25,14 @@ class NodeItem { template void set_input(const std::string &name, const T &value, const std::string &mx_type); - void set_input(const std::string &name, const NodeItem &item); + void set_input(const std::string &name, + const NodeItem &item, + const std::string &output_name = ""); void set_input(const std::string &name, const MaterialX::ValuePtr value); - void set_input(const std::string &name, const MaterialX::NodePtr node); + void set_input(const std::string &name, + const MaterialX::NodePtr node, + const std::string &output_name = ""); + void add_output(const std::string &name, const std::string &mx_type); operator bool() const; NodeItem operator+(const NodeItem &other) const; @@ -79,7 +84,9 @@ class NodeItem { std::function func) const; static MaterialX::ValuePtr float_to_type(float v, std::string mx_type); /* Functions for adjusting values to make equal types */ - static bool adjust_types(MaterialX::ValuePtr &val1, MaterialX::ValuePtr &val2, std::string &mx_type); + static bool adjust_types(MaterialX::ValuePtr &val1, + MaterialX::ValuePtr &val2, + std::string &mx_type); static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type); }; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 61bda4d3262..edbdffd6f09 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -18,12 +18,12 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph, NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type, - bool accessory) + bool noname) { NodeItem res = empty(); res.node = graph->addNode(mx_category, - accessory ? MaterialX::EMPTY_STRING : - MaterialX::createValidName(node->name), + noname ? MaterialX::EMPTY_STRING : + MaterialX::createValidName(node->name), mx_type); return res; } @@ -110,7 +110,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) /* Getting required NodeParser object */ std::unique_ptr parser; - switch (in_node->type) { + switch (in_node->typeinfo->type) { case SH_NODE_BSDF_PRINCIPLED: parser = std::make_unique(graph, depsgraph, material, in_node); break; @@ -126,6 +126,15 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) case SH_NODE_TEX_IMAGE: parser = std::make_unique(graph, depsgraph, material, in_node); break; + case SH_NODE_TEX_ENVIRONMENT: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; + case SH_NODE_TEX_NOISE: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; + case SH_NODE_TEX_CHECKER: + parser = std::make_unique(graph, depsgraph, material, in_node); + break; default: // TODO: warning log return res; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 4849e430bc3..86d1935e41f 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -31,7 +31,7 @@ class NodeParser { protected: NodeItem create_node(const std::string &mx_category, const std::string &mx_type, - bool accessory = false); + bool noname = true); NodeItem get_input_default(const std::string &name); NodeItem get_input_default(int index); NodeItem get_input_link(const std::string &name); @@ -64,6 +64,9 @@ DECLARE_PARSER(InvertNodeParser) DECLARE_PARSER(MathNodeParser) DECLARE_PARSER(MixRGBNodeParser) DECLARE_PARSER(OutputMaterialNodeParser) +DECLARE_PARSER(TexCheckerNodeParser) +DECLARE_PARSER(TexEnvironmentNodeParser) DECLARE_PARSER(TexImageNodeParser) +DECLARE_PARSER(TexNoiseNodeParser) } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index 94a106c40c0..81d00737027 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -11,7 +11,7 @@ NodeItem OutputMaterialNodeParser::compute() NodeItem node = empty(); NodeItem surface = get_input_link("Surface"); if (surface) { - node = create_node("surfacematerial", "material"); + node = create_node("surfacematerial", "material", false); node.set_input("surfaceshader", surface); } return node; diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc new file mode 100644 index 00000000000..f04f8ed2c45 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -0,0 +1,52 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem TexCheckerNodeParser::compute() +{ + NodeItem scale = get_input_value("Scale"); + NodeItem color1 = get_input_value("Color1"); + NodeItem color2 = get_input_value("Color2"); + + if (scale.value && scale.type() == "float") { + float v = scale.value->asA(); + scale = value(MaterialX::Vector2(v, v)); + } + /* Modifier to follow Cycles result */ + scale = scale * value(4.0f); + + NodeItem texcoord = create_node("texcoord", "vector2"); + NodeItem place2d = create_node("place2d", "vector2"); + place2d.set_input("texcoord", texcoord * scale); + + /* TODO: fix offset: + * place2d.set_input("offset", offset); */ + + NodeItem separate = create_node("separate2", "multioutput"); + separate.set_input("in", place2d); + separate.add_output("outx", "float"); + separate.add_output("outy", "float"); + + NodeItem modulo_x = create_node("modulo", "float"); + modulo_x.set_input("in1", separate, "outx"); + modulo_x.set_input("in2", value(2.0f)); + + NodeItem modulo_y = create_node("modulo", "float"); + modulo_y.set_input("in1", separate, "outy"); + modulo_y.set_input("in2", value(2.0f)); + + NodeItem ifequal = + (modulo_x.floor() + modulo_y.floor()).if_else("==", value(1.0f), value(0.0f), value(1.0f)); + + NodeItem res = create_node("mix", "color3", false); + res.set_input("fg", color1.to_color3()); + res.set_input("bg", color2.to_color3()); + res.set_input("mix", ifequal); + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc new file mode 100644 index 00000000000..a6048db0412 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc @@ -0,0 +1,33 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +#include "hydra/image.h" + +#include "DEG_depsgraph_query.h" + +namespace blender::nodes::materialx { + +NodeItem TexEnvironmentNodeParser::compute() +{ + Image *image = (Image *)node->id; + NodeTexEnvironment *tex = static_cast(node->storage); + Scene *scene = DEG_get_input_scene(depsgraph); + Main *bmain = DEG_get_bmain(depsgraph); + std::string image_path; + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains + * pretty general code, so could be moved from bf_usd project. */ +#ifdef WITH_HYDRA + image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); +#endif + + NodeItem texcoord = create_node("texcoord", "vector2"); + NodeItem res = create_node("image", "color3", false); + res.set_input("file", image_path, "filename"); + res.set_input("texcoord", texcoord); + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc index 6c0239459e0..9d0d3d03319 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -17,14 +17,14 @@ NodeItem TexImageNodeParser::compute() Scene *scene = DEG_get_input_scene(depsgraph); Main *bmain = DEG_get_bmain(depsgraph); std::string image_path; - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contain + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains * pretty general code, so could be moved from bf_usd project. */ #ifdef WITH_HYDRA image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); #endif - NodeItem texcoord = create_node("texcoord", "vector2", true); - NodeItem res = create_node("image", "color3"); + NodeItem texcoord = create_node("texcoord", "vector2"); + NodeItem res = create_node("image", "color3", false); res.set_input("file", image_path, "filename"); res.set_input("texcoord", texcoord); return res; diff --git a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc new file mode 100644 index 00000000000..63268d1fd8c --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/tex_noise.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 TexNoiseNodeParser::compute() +{ + NodeItem scale = get_input_value("Scale"); + NodeItem detail = get_input_value("Detail"); + NodeItem lacunarity = get_input_value("Lacunarity"); + + if (detail.value && detail.type() == "float") { + detail = value(int(detail.value->asA())); + } + + NodeItem texcoord = create_node("position", "vector3"); + + NodeItem res = create_node("fractal3d", "color3", false); + res.set_input("position", texcoord * scale); + res.set_input("octaves", detail); + res.set_input("lacunarity", lacunarity); + return res; +} + +} // namespace blender::nodes::materialx -- 2.30.2 From fa0aea502f030b8b5c73f0ff0c3b7e3d0d8ea495 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 31 Aug 2023 20:11:06 +0200 Subject: [PATCH 08/40] MaterialX logging ### Purpose Change debug printf to CLOG logger. Add other logging. ### Technical steps 1. Applied CLOG logger to `bf_nodes_shader` project. 2. Changed debug `printf` to logging. Added other logging. 3. Fixed "Use MaterialX" in `rna_render.cc`. ### Notes Don't use `--log-show-basename` blender running flag in Windows, because of clog crash due to incorrect path separator for `bf_nodes_shader` project. Pull Request: https://projects.blender.org/DagerD/blender/pulls/7 --- source/blender/makesrna/intern/rna_render.cc | 2 +- source/blender/nodes/shader/CMakeLists.txt | 9 ++++--- .../nodes/shader/materialx/material.cc | 9 +++++-- .../blender/nodes/shader/materialx/material.h | 8 +++++-- .../shader/materialx/nodes/bsdf_principled.cc | 24 +++++++++++++------ .../nodes/shader/materialx/nodes/math.cc | 16 ++++++------- .../nodes/shader/materialx/nodes/node_item.cc | 21 ++++++++++------ .../shader/materialx/nodes/node_parser.cc | 7 +++--- 8 files changed, 62 insertions(+), 34 deletions(-) diff --git a/source/blender/makesrna/intern/rna_render.cc b/source/blender/makesrna/intern/rna_render.cc index 75efabbb1a5..c681bd398a5 100644 --- a/source/blender/makesrna/intern/rna_render.cc +++ b/source/blender/makesrna/intern/rna_render.cc @@ -1010,7 +1010,7 @@ static void rna_def_render_engine(BlenderRNA *brna) prop = RNA_def_property(srna, "bl_use_materialx", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "type->flag", RE_USE_MATERIALX); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_ui_text(prop, "Use Material", "Use MaterialX for exporting materials to Hydra"); + RNA_def_property_ui_text(prop, "Use MaterialX", "Use MaterialX for exporting materials to Hydra"); RNA_define_verify_sdna(true); } diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 991128fec7f..1dec91b8b3a 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -24,7 +24,8 @@ set(INC if(WITH_HYDRA) list(APPEND INC ../../io/usd - ) + ../../../../intern/clog +) add_definitions(-DWITH_HYDRA) endif() @@ -144,8 +145,6 @@ set(LIB ) if(WITH_MATERIALX) - list(APPEND LIB MaterialXCore) - list(APPEND LIB MaterialXFormat) list(APPEND SRC materialx/material.cc materialx/nodes/bsdf_principled.cc @@ -164,6 +163,10 @@ if(WITH_MATERIALX) materialx/nodes/node_item.h materialx/nodes/node_parser.h ) + list(APPEND LIB + MaterialXCore + MaterialXFormat + ) endif() if(WITH_FREESTYLE) diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 5fec3563571..502ea74f5fd 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -5,13 +5,18 @@ #include "material.h" #include "nodes/node_parser.h" -#include #include +#include "DEG_depsgraph.h" + +#include "DNA_material_types.h" + #include "NOD_shader.h" namespace blender::nodes::materialx { +CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader"); + static void export_nodegraph(MaterialX::GraphElement *graph, Depsgraph *depsgraph, Material *material) @@ -48,7 +53,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater create_standard_surface(doc.get(), material); } std::string str = MaterialX::writeToXmlString(doc); - printf("\nMaterial: %s\n%s\n", material->id.name, str.c_str()); + CLOG_INFO(LOG_MATERIALX_SHADER, 1, "Material: %s\n%s", material->id.name, str.c_str()); return doc; } diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h index 1784c42349b..b32f3ff2962 100644 --- a/source/blender/nodes/shader/materialx/material.h +++ b/source/blender/nodes/shader/materialx/material.h @@ -6,11 +6,15 @@ #include -#include "DEG_depsgraph.h" -#include "DNA_material_types.h" +#include "CLG_log.h" + +struct Depsgraph; +struct Material; namespace blender::nodes::materialx { +extern struct CLG_LogRef *LOG_MATERIALX_SHADER; + MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); } // 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 a87a0782881..5a5e9f7c053 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -72,8 +72,12 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("base", 1.0, "float"); res.set_input("base_color", base_color.to_color3()); res.set_input("diffuse_roughness", roughness); - res.set_input("normal", normal); - res.set_input("tangent", tangent); + if (normal) { + res.set_input("normal", normal); + } + if (tangent) { + res.set_input("tangent", tangent); + } if (metallic != zero) { res.set_input("metalness", metallic); @@ -84,8 +88,10 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("specular_color", base_color.to_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 (anisotropic) { + res.set_input("specular_anisotropy", anisotropic); + res.set_input("specular_rotation", anisotropic_rotation); + } } if (transmission != zero) { @@ -98,7 +104,9 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("subsurface", subsurface); res.set_input("subsurface_color", subsurface_color); res.set_input("subsurface_radius", subsurface_radius); - res.set_input("subsurface_anisotropy", anisotropic); + if (anisotropic) { + res.set_input("subsurface_anisotropy", anisotropic); + } } if (sheen != zero) { @@ -112,8 +120,10 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("coat_color", base_color.to_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 (anisotropic) { + res.set_input("coat_anisotropy", anisotropic); + res.set_input("coat_rotation", anisotropic_rotation); + } res.set_input("coat_normal", clearcoat_normal); } diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index 9fce9a7457d..8787bf2ca39 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -3,16 +3,14 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "node_parser.h" +#include "../material.h" namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { /* TODO: finish some math operations */ - auto op = node->custom1; - printf("%d\n", int(op)); - NodeItem res = empty(); /* Single operand operations */ @@ -123,13 +121,13 @@ NodeItem MathNodeParser::compute() res = x.atan2(y); break; case NODE_MATH_SNAP: - // res = ; + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; case NODE_MATH_PINGPONG: - // res = ; + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; case NODE_MATH_FLOORED_MODULO: - // res = ; + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; default: { @@ -137,7 +135,7 @@ NodeItem MathNodeParser::compute() NodeItem z = get_input_value(2); switch (op) { case NODE_MATH_WRAP: - // res = ; + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; case NODE_MATH_COMPARE: res = z.if_else("<", (x - y).abs(), value(1.0f), value(0.0f)); @@ -146,10 +144,10 @@ NodeItem MathNodeParser::compute() res = x * y + z; break; case NODE_MATH_SMOOTH_MIN: - // res = ; + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; case NODE_MATH_SMOOTH_MAX: - // res = ; + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; default: diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index b5b85fb6eea..f3cf3779058 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "node_item.h" +#include "../material.h" #include "BLI_assert.h" #include "BLI_utildefines.h" @@ -26,6 +27,9 @@ void NodeItem::set_input(const std::string &name, else if (item.node) { set_input(name, item.node, output_name); } + else { + CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str()); + } } void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) @@ -218,6 +222,9 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const auto v = value->asA(); f = v[0] + v[1] + v[2] + v[3]; } + else { + BLI_assert_unreachable(); + } d.value = MaterialX::Value::createValue(f); } return d; @@ -369,27 +376,27 @@ NodeItem NodeItem::exp() const NodeItem NodeItem::to_color3() const { - std::string t = type(); + std::string mx_type = type(); NodeItem res = empty(); if (value) { MaterialX::Color3 c; - if (t == "float") { + if (mx_type == "float") { float v = value->asA(); c = {v, v, v}; } - else if (t == "color3") { + else if (mx_type == "color3") { auto v = value->asA(); c = {v[0], v[1], v[2]}; } - else if (t == "color4") { + else if (mx_type == "color4") { auto v = value->asA(); c = {v[0], v[1], v[2]}; } - else if (t == "vector3") { + else if (mx_type == "vector3") { auto v = value->asA(); c = {v[0], v[1], v[2]}; } - else if (t == "vector4") { + else if (mx_type == "vector4") { auto v = value->asA(); c = {v[0], v[1], v[2]}; } @@ -399,7 +406,7 @@ NodeItem NodeItem::to_color3() const res.value = MaterialX::Value::createValue(c); } else if (node) { - if (t != "color3") { + if (mx_type != "color3") { return res; } res.node = node; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index edbdffd6f09..2c8974406d9 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -3,8 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "node_parser.h" +#include "../material.h" -#include +#include "BKE_node_runtime.hh" namespace blender::nodes::materialx { @@ -82,7 +83,7 @@ NodeItem NodeParser::get_input_default(const bNodeSocket &socket) MaterialX::Color4(v[0], v[1], v[2], v[3])); } break; default: { - // TODO log warn + CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type); } } return res; @@ -136,7 +137,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) parser = std::make_unique(graph, depsgraph, material, in_node); break; default: - // TODO: warning log + CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported node: %s (%d)", in_node->name, in_node->type); return res; } -- 2.30.2 From e1248d2f2822f56b3e02c831f1ff420f4562027b Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Mon, 4 Sep 2023 10:09:46 +0200 Subject: [PATCH 09/40] Code improvements/fixes ### Purpose There is set of code improvements and bug fixes required in NodeParser system. ### Technical steps 1. Separated `OutputMaterialNodeParser` declaration to `output_material.h`. Added more functionality. 2. Added `NodeParser::compute_full()` with additional logging and naming of mx_node. 3. Fix: added check if node was already computed. 4. Fixed TexChecker. 5. Code improvements, renamings, code cleanup. ### Notes There is no need additional scaling in TexChecker, it was removed. There is issue with UV map on default cube, which should be fixed another way. Pull Request: https://projects.blender.org/DagerD/blender/pulls/8 --- source/blender/nodes/shader/CMakeLists.txt | 1 + .../nodes/shader/materialx/material.cc | 46 +++----- .../blender/nodes/shader/materialx/material.h | 4 +- .../shader/materialx/nodes/bsdf_principled.cc | 6 +- .../nodes/shader/materialx/nodes/math.cc | 4 +- .../shader/materialx/nodes/node_parser.cc | 109 ++++++++++-------- .../shader/materialx/nodes/node_parser.h | 22 ++-- .../shader/materialx/nodes/output_material.cc | 51 ++++++-- .../shader/materialx/nodes/output_material.h | 22 ++++ .../shader/materialx/nodes/tex_checker.cc | 11 +- .../shader/materialx/nodes/tex_environment.cc | 10 +- .../nodes/shader/materialx/nodes/tex_image.cc | 10 +- .../nodes/shader/materialx/nodes/tex_noise.cc | 2 +- 13 files changed, 175 insertions(+), 123 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/output_material.h diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 1dec91b8b3a..114ab576101 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -162,6 +162,7 @@ if(WITH_MATERIALX) materialx/material.h materialx/nodes/node_item.h materialx/nodes/node_parser.h + materialx/nodes/output_material.h ) list(APPEND LIB MaterialXCore diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 502ea74f5fd..1e88124b357 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -3,7 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "material.h" -#include "nodes/node_parser.h" +#include "nodes/output_material.h" #include @@ -17,43 +17,27 @@ namespace blender::nodes::materialx { CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader"); -static void export_nodegraph(MaterialX::GraphElement *graph, - Depsgraph *depsgraph, - Material *material) +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, + Material *material, + const std::string &socket_name) { - material->nodetree->ensure_topology_cache(); + CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name); - bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); - OutputMaterialNodeParser parser(graph, depsgraph, material, output_node); - parser.compute(); -} - -static void create_standard_surface(MaterialX::GraphElement *graph, Material *material) -{ - MaterialX::NodePtr standard_surface = graph->addNode( - "standard_surface", MaterialX::EMPTY_STRING, "surfaceshader"); - - standard_surface->addInput("base", "float")->setValue(1.0); - standard_surface->addInput("base_color", "color3") - ->setValue(MaterialX::Color3(material->r, material->g, material->b)); - - MaterialX::NodePtr surfacematerial = graph->addNode( - "surfacematerial", MaterialX::EMPTY_STRING, "material"); - surfacematerial->addInput(standard_surface->getType(), standard_surface->getType()) - ->setNodeName(standard_surface->getName()); -} - -MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material) -{ MaterialX::DocumentPtr doc = MaterialX::createDocument(); if (material->use_nodes) { - export_nodegraph(doc.get(), depsgraph, material); + material->nodetree->ensure_topology_cache(); + bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); + OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute(socket_name); } else { - create_standard_surface(doc.get(), material); + OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default(); } - std::string str = MaterialX::writeToXmlString(doc); - CLOG_INFO(LOG_MATERIALX_SHADER, 1, "Material: %s\n%s", material->id.name, str.c_str()); + + CLOG_INFO(LOG_MATERIALX_SHADER, + 2, + "Material: %s\n%s", + material->id.name, + MaterialX::writeToXmlString(doc).c_str()); return doc; } diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h index b32f3ff2962..4c90febce6c 100644 --- a/source/blender/nodes/shader/materialx/material.h +++ b/source/blender/nodes/shader/materialx/material.h @@ -15,6 +15,8 @@ namespace blender::nodes::materialx { extern struct CLG_LogRef *LOG_MATERIALX_SHADER; -MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, + Material *material, + const std::string &socket_name = "Surface"); } // 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 5a5e9f7c053..43a046cc929 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -68,7 +68,7 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem tangent = get_input_link("Tangent"); /* Creating standard_surface */ - NodeItem res = create_node("standard_surface", "surfaceshader", false); + NodeItem res = create_node("standard_surface", "surfaceshader"); res.set_input("base", 1.0, "float"); res.set_input("base_color", base_color.to_color3()); res.set_input("diffuse_roughness", roughness); @@ -90,7 +90,9 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("specular_IOR", ior); if (anisotropic) { res.set_input("specular_anisotropy", anisotropic); - res.set_input("specular_rotation", anisotropic_rotation); + if (anisotropic_rotation) { + res.set_input("specular_rotation", anisotropic_rotation); + } } } diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index 8787bf2ca39..cbd5d6fd023 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -10,7 +10,7 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { /* TODO: finish some math operations */ - auto op = node->custom1; + auto op = node_->custom1; NodeItem res = empty(); /* Single operand operations */ @@ -158,7 +158,7 @@ NodeItem MathNodeParser::compute() } } - bool clamp_output = node->custom2 != 0; + bool clamp_output = node_->custom2 != 0; if (clamp_output && res) { res = res.clamp(); } diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 2c8974406d9..0b7c6e82ad6 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -12,56 +12,59 @@ namespace blender::nodes::materialx { NodeParser::NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, - const bNode *node) - : graph(graph), depsgraph(depsgraph), material(material), node(node) + const bNode *node, + const bNodeSocket *socket_out) + : graph_(graph), depsgraph_(depsgraph), material_(material), node_(node), socket_out_(socket_out) { } -NodeItem NodeParser::create_node(const std::string &mx_category, - const std::string &mx_type, - bool noname) +std::string NodeParser::node_name(const bNode *node, const bNodeSocket *socket_out) +{ + return MaterialX::createValidName(node->output_sockets().size() <= 1 ? + std::string(node->name) : + std::string(node->name) + "_" + socket_out->name); +} + +NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type) { NodeItem res = empty(); - res.node = graph->addNode(mx_category, - noname ? MaterialX::EMPTY_STRING : - MaterialX::createValidName(node->name), - mx_type); + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); return res; } NodeItem NodeParser::get_input_default(const std::string &name) { - return get_input_default(node->input_by_identifier(name)); + return get_input_default(node_->input_by_identifier(name)); } NodeItem NodeParser::get_input_default(int index) { - return get_input_default(node->input_socket(index)); + return get_input_default(node_->input_socket(index)); } NodeItem NodeParser::get_input_link(const std::string &name) { - return get_input_link(node->input_by_identifier(name)); + return get_input_link(node_->input_by_identifier(name)); } NodeItem NodeParser::get_input_link(int index) { - return get_input_link(node->input_socket(index)); + return get_input_link(node_->input_socket(index)); } NodeItem NodeParser::get_input_value(const std::string &name) { - return get_input_value(node->input_by_identifier(name)); + return get_input_value(node_->input_by_identifier(name)); } NodeItem NodeParser::get_input_value(int index) { - return get_input_value(node->input_socket(index)); + return get_input_value(node_->input_socket(index)); } NodeItem NodeParser::empty() const { - return NodeItem(graph); + return NodeItem(graph_); } NodeItem NodeParser::get_input_default(const bNodeSocket &socket) @@ -98,50 +101,46 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) return res; } - const bNode *in_node = link->fromnode; + const bNode *from_node = link->fromnode; /* Passing NODE_REROUTE nodes */ - while (in_node->type == NODE_REROUTE) { - link = in_node->input_socket(0).link; + while (from_node->type == NODE_REROUTE) { + link = from_node->input_socket(0).link; if (!(link && link->is_used())) { return res; } - in_node = link->fromnode; + from_node = link->fromnode; } - /* Getting required NodeParser object */ - std::unique_ptr parser; - switch (in_node->typeinfo->type) { - case SH_NODE_BSDF_PRINCIPLED: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_INVERT: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_MATH: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_MIX_RGB_LEGACY: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_TEX_IMAGE: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_TEX_ENVIRONMENT: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_TEX_NOISE: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; - case SH_NODE_TEX_CHECKER: - parser = std::make_unique(graph, depsgraph, material, in_node); - break; + /* Checking if node was already computed */ + res.node = graph_->getNode(node_name(from_node, link->fromsock)); + if (res.node) { + return res; + } + + /* Computing from_node with required NodeParser object */ +#define CASE_NODE_TYPE(type, T) \ + case type: \ + res = T(graph_, depsgraph_, material_, from_node, link->fromsock).compute_full(); \ + break; + + switch (from_node->typeinfo->type) { + CASE_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser) + 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_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) + default: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported node: %s (%d)", in_node->name, in_node->type); - return res; + CLOG_WARN(LOG_MATERIALX_SHADER, + "Unsupported node: %s [%d]", + from_node->name, + from_node->typeinfo->type); } - res = parser->compute(); return res; } @@ -154,4 +153,14 @@ NodeItem NodeParser::get_input_value(const bNodeSocket &socket) return res; } +NodeItem NodeParser::compute_full() +{ + CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type); + NodeItem res = compute(); + if (res.node) { + res.node->setName(node_name(node_, socket_out_)); + } + return res; +} + } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 86d1935e41f..bb9986896d9 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -13,25 +13,25 @@ namespace blender::nodes::materialx { class NodeParser { - public: - MaterialX::GraphElement *graph; - const Depsgraph *depsgraph; - const Material *material; - const bNode *node; + protected: + MaterialX::GraphElement *graph_; + const Depsgraph *depsgraph_; + const Material *material_; + const bNode *node_; + const bNodeSocket *socket_out_; public: NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, - const bNode *node); + const bNode *node, + const bNodeSocket *socket_out); virtual ~NodeParser() = default; - virtual NodeItem compute() = 0; protected: - NodeItem create_node(const std::string &mx_category, - const std::string &mx_type, - bool noname = true); + static std::string node_name(const bNode *node, const bNodeSocket *socket_out); + NodeItem create_node(const std::string &mx_category, const std::string &mx_type); NodeItem get_input_default(const std::string &name); NodeItem get_input_default(int index); NodeItem get_input_link(const std::string &name); @@ -45,6 +45,7 @@ class NodeParser { NodeItem get_input_default(const bNodeSocket &socket); NodeItem get_input_link(const bNodeSocket &socket); NodeItem get_input_value(const bNodeSocket &socket); + NodeItem compute_full(); }; template NodeItem NodeParser::value(const T &data) const @@ -63,7 +64,6 @@ DECLARE_PARSER(BSDFPrincipledNodeParser) DECLARE_PARSER(InvertNodeParser) DECLARE_PARSER(MathNodeParser) DECLARE_PARSER(MixRGBNodeParser) -DECLARE_PARSER(OutputMaterialNodeParser) DECLARE_PARSER(TexCheckerNodeParser) DECLARE_PARSER(TexEnvironmentNodeParser) DECLARE_PARSER(TexImageNodeParser) diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index 81d00737027..5b5d9d0b7c6 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -2,19 +2,56 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "node_parser.h" +#include "output_material.h" namespace blender::nodes::materialx { +OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node) + : NodeParser(graph, depsgraph, material, node, nullptr) +{ +} NodeItem OutputMaterialNodeParser::compute() { - NodeItem node = empty(); - NodeItem surface = get_input_link("Surface"); - if (surface) { - node = create_node("surfacematerial", "material", false); - node.set_input("surfaceshader", surface); + return empty(); +} + +NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name) +{ + NodeItem surface = empty(); + if (node_) { + surface = get_input_link(socket_name); } - return node; + else { + surface = create_node("standard_surface", "surfaceshader"); + surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f))); + } + NodeItem res = create_node("surfacematerial", "material"); + res.node->setName(node_name(node_, nullptr)); + res.set_input("surfaceshader", surface); + return res; +} + +NodeItem OutputMaterialNodeParser::compute_default() +{ + NodeItem surface = create_node("standard_surface", "surfaceshader"); + surface.set_input("base_color", value(MaterialX::Color3(material_->r, material_->g, material_->b))); + surface.set_input("diffuse_roughness", value(material_->roughness)); + if (material_->metallic > 0.0f) { + surface.set_input("metalness", value(material_->metallic)); + } + if (material_->spec) { + surface.set_input("specular", value(material_->spec)); + surface.set_input("specular_color", value(material_->spec)); + surface.set_input("specular_roughness", value(material_->roughness)); + } + + NodeItem res = create_node("surfacematerial", "material"); + res.node->setName("Material_Default"); + res.set_input("surfaceshader", surface); + return res; } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.h b/source/blender/nodes/shader/materialx/nodes/output_material.h new file mode 100644 index 00000000000..986c926f33d --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/output_material.h @@ -0,0 +1,22 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +class OutputMaterialNodeParser : public NodeParser { + public: + OutputMaterialNodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node); + NodeItem compute() override; + NodeItem compute(const std::string &socket_name); + NodeItem compute_default(); +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index f04f8ed2c45..63266bd5081 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -16,16 +16,11 @@ NodeItem TexCheckerNodeParser::compute() float v = scale.value->asA(); scale = value(MaterialX::Vector2(v, v)); } - /* Modifier to follow Cycles result */ - scale = scale * value(4.0f); NodeItem texcoord = create_node("texcoord", "vector2"); NodeItem place2d = create_node("place2d", "vector2"); place2d.set_input("texcoord", texcoord * scale); - /* TODO: fix offset: - * place2d.set_input("offset", offset); */ - NodeItem separate = create_node("separate2", "multioutput"); separate.set_input("in", place2d); separate.add_output("outx", "float"); @@ -42,9 +37,9 @@ NodeItem TexCheckerNodeParser::compute() NodeItem ifequal = (modulo_x.floor() + modulo_y.floor()).if_else("==", value(1.0f), value(0.0f), value(1.0f)); - NodeItem res = create_node("mix", "color3", false); - res.set_input("fg", color1.to_color3()); - res.set_input("bg", color2.to_color3()); + NodeItem res = create_node("mix", "color3"); + res.set_input("bg", color1.to_color3()); + res.set_input("fg", color2.to_color3()); res.set_input("mix", ifequal); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc index a6048db0412..f2aede4cb4b 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc @@ -12,10 +12,10 @@ namespace blender::nodes::materialx { NodeItem TexEnvironmentNodeParser::compute() { - Image *image = (Image *)node->id; - NodeTexEnvironment *tex = static_cast(node->storage); - Scene *scene = DEG_get_input_scene(depsgraph); - Main *bmain = DEG_get_bmain(depsgraph); + Image *image = (Image *)node_->id; + NodeTexEnvironment *tex = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); std::string image_path; /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains * pretty general code, so could be moved from bf_usd project. */ @@ -24,7 +24,7 @@ NodeItem TexEnvironmentNodeParser::compute() #endif NodeItem texcoord = create_node("texcoord", "vector2"); - NodeItem res = create_node("image", "color3", false); + NodeItem res = create_node("image", "color3"); res.set_input("file", image_path, "filename"); res.set_input("texcoord", texcoord); return res; diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc index 9d0d3d03319..2a2625259ef 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -12,10 +12,10 @@ namespace blender::nodes::materialx { NodeItem TexImageNodeParser::compute() { - Image *image = (Image *)node->id; - NodeTexImage *tex = static_cast(node->storage); - Scene *scene = DEG_get_input_scene(depsgraph); - Main *bmain = DEG_get_bmain(depsgraph); + Image *image = (Image *)node_->id; + NodeTexImage *tex = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); std::string image_path; /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains * pretty general code, so could be moved from bf_usd project. */ @@ -24,7 +24,7 @@ NodeItem TexImageNodeParser::compute() #endif NodeItem texcoord = create_node("texcoord", "vector2"); - NodeItem res = create_node("image", "color3", false); + NodeItem res = create_node("image", "color3"); res.set_input("file", image_path, "filename"); res.set_input("texcoord", texcoord); return res; diff --git a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc index 63268d1fd8c..d3a016c6320 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc @@ -18,7 +18,7 @@ NodeItem TexNoiseNodeParser::compute() NodeItem texcoord = create_node("position", "vector3"); - NodeItem res = create_node("fractal3d", "color3", false); + NodeItem res = create_node("fractal3d", "color3"); res.set_input("position", texcoord * scale); res.set_input("octaves", detail); res.set_input("lacunarity", lacunarity); -- 2.30.2 From 127fff610856b002a21d9dfb5a08280d00cb8bfd Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 5 Sep 2023 12:03:02 +0200 Subject: [PATCH 10/40] Implement type conversion for NodeItem ### Purpose `NodeItem` requires `convert()` method for node type conversion. This will simplify arithmetic and other methods. ### Technical steps 1. Moved `NodeItem` type` and conditional type` in `if_else` from `string` to `enum` values. 2. Implemented `NodeItem::convert()` method. 3. Simplified `set_input` methods. 4. Refactor: rearranged functions in `NodeItem` to satisfy blender code style. Pull Request: https://projects.blender.org/DagerD/blender/pulls/9 --- .../shader/materialx/nodes/bsdf_principled.cc | 32 +- .../nodes/shader/materialx/nodes/math.cc | 8 +- .../nodes/shader/materialx/nodes/node_item.cc | 909 ++++++++++-------- .../nodes/shader/materialx/nodes/node_item.h | 79 +- .../shader/materialx/nodes/node_parser.cc | 17 +- .../shader/materialx/nodes/output_material.cc | 3 +- .../shader/materialx/nodes/tex_checker.cc | 27 +- .../nodes/shader/materialx/nodes/tex_noise.cc | 7 +- 8 files changed, 621 insertions(+), 461 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 43a046cc929..a8829ddf92f 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -15,12 +15,8 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem base_color = get_input_value("Base Color"); NodeItem subsurface = get_input_value("Subsurface"); - NodeItem subsurface_radius = empty(); - NodeItem subsurface_color = empty(); - if (subsurface != zero) { - subsurface_radius = get_input_value("Subsurface Radius"); - subsurface_color = get_input_value("Subsurface Color"); - } + NodeItem subsurface_radius = get_input_value("Subsurface Radius"); + NodeItem subsurface_color = get_input_value("Subsurface Color"); NodeItem metallic = get_input_value("Metallic"); NodeItem specular = get_input_value("Specular"); @@ -70,7 +66,7 @@ NodeItem BSDFPrincipledNodeParser::compute() /* Creating standard_surface */ NodeItem res = create_node("standard_surface", "surfaceshader"); res.set_input("base", 1.0, "float"); - res.set_input("base_color", base_color.to_color3()); + res.set_input("base_color", base_color, NodeItem::Type::Color3); res.set_input("diffuse_roughness", roughness); if (normal) { res.set_input("normal", normal); @@ -85,7 +81,7 @@ NodeItem BSDFPrincipledNodeParser::compute() if (specular != zero) { res.set_input("specular", specular); - res.set_input("specular_color", base_color.to_color3()); + res.set_input("specular_color", base_color, NodeItem::Type::Color3); res.set_input("specular_roughness", roughness); res.set_input("specular_IOR", ior); if (anisotropic) { @@ -98,28 +94,26 @@ NodeItem BSDFPrincipledNodeParser::compute() if (transmission != zero) { res.set_input("transmission", transmission); - res.set_input("transmission_color", base_color.to_color3()); + res.set_input("transmission_color", base_color, NodeItem::Type::Color3); res.set_input("transmission_extra_roughness", transmission_roughness); } - if (subsurface != zero) { - 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", subsurface); + res.set_input("subsurface_color", subsurface_color); + res.set_input("subsurface_radius", subsurface_radius); + if (anisotropic) { + res.set_input("subsurface_anisotropy", anisotropic); } if (sheen != zero) { res.set_input("sheen", sheen); - res.set_input("sheen_color", base_color.to_color3()); + 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.to_color3()); + 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) { @@ -131,7 +125,7 @@ NodeItem BSDFPrincipledNodeParser::compute() if (emission != zero) { res.set_input("emission", emission_strength); - res.set_input("emission_color", emission); + res.set_input("emission_color", emission, NodeItem::Type::Color3); } return res; diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index cbd5d6fd023..598c80a2fae 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -2,8 +2,8 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "node_parser.h" #include "../material.h" +#include "node_parser.h" namespace blender::nodes::materialx { @@ -109,10 +109,10 @@ NodeItem MathNodeParser::compute() res = x.max(y); break; case NODE_MATH_LESS_THAN: - res = x.if_else("<", y, value(1.0f), value(0.0f)); + res = x.if_else(NodeItem::CompareOp::Less, y, value(1.0f), value(0.0f)); break; case NODE_MATH_GREATER_THAN: - res = x.if_else(">", y, value(1.0f), value(0.0f)); + res = x.if_else(NodeItem::CompareOp::Greater, y, value(1.0f), value(0.0f)); break; case NODE_MATH_MODULO: res = x % y; @@ -138,7 +138,7 @@ NodeItem MathNodeParser::compute() CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; case NODE_MATH_COMPARE: - res = z.if_else("<", (x - y).abs(), value(1.0f), value(0.0f)); + res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), value(1.0f), value(0.0f)); break; case NODE_MATH_MULTIPLY_ADD: res = x * y + z; diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index f3cf3779058..5e6df0555fc 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -12,73 +12,6 @@ namespace blender::nodes::materialx { NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} -NodeItem NodeItem::empty() const -{ - return NodeItem(graph_); -} - -void NodeItem::set_input(const std::string &name, - const NodeItem &item, - const std::string &output_name) -{ - if (item.value) { - set_input(name, item.value); - } - else if (item.node) { - set_input(name, item.node, output_name); - } - else { - CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str()); - } -} - -void NodeItem::set_input(const std::string &name, const MaterialX::ValuePtr value) -{ - std::string mx_type = value->getTypeString(); - if (mx_type == "float") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "integer") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "vector2") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "vector3") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "vector4") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "color3") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "color4") { - set_input(name, value->asA(), mx_type); - } - else if (mx_type == "string") { - set_input(name, value->asA(), mx_type); - } - else { - BLI_assert_unreachable(); - } -} - -void NodeItem::set_input(const std::string &name, - const MaterialX::NodePtr node, - const std::string &output_name) -{ - this->node->setConnectedNode(name, node); - if (output_name != "") { - this->node->setConnectedOutput("in1", node->getOutput(output_name)); - } -} - -void NodeItem::add_output(const std::string &name, const std::string &mx_type) -{ - node->addOutput(name, mx_type); -} - NodeItem::operator bool() const { return value || node; @@ -135,32 +68,13 @@ bool NodeItem::operator==(const NodeItem &other) const return false; } - std::string mx_type; - auto val1 = value; - auto val2 = other.value; - if (!adjust_types(val1, val2, mx_type)) { + NodeItem item1 = *this; + NodeItem item2 = other; + Type to_type = adjust_types(item1, item2); + if (to_type == Type::Empty) { return false; } - if (mx_type == "float") { - return val1->asA() == val2->asA(); - } - if (mx_type == "color3") { - return val1->asA() == val2->asA(); - } - if (mx_type == "color4") { - return val1->asA() == val2->asA(); - } - if (mx_type == "vector2") { - return val1->asA() == val2->asA(); - } - if (mx_type == "vector3") { - return val1->asA() == val2->asA(); - } - if (mx_type == "vector4") { - return val1->asA() == val2->asA(); - } - - return false; + return item1.value->getValueString() == item2.value->getValueString(); } bool NodeItem::operator!=(const NodeItem &other) const @@ -197,98 +111,46 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const { NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); if (d.value) { - std::string mx_type = d.type(); + Type mx_type = d.type(); float f = 0.0f; - if (mx_type == "float") { - f = value->asA(); - } - else if (mx_type == "color3") { - auto v = value->asA(); - f = v[0] + v[1] + v[2]; - } - else if (mx_type == "color4") { - auto v = value->asA(); - f = v[0] + v[1] + v[2] + v[3]; - } - else if (mx_type == "vector2") { - auto v = value->asA(); - f = v[0] + v[1]; - } - else if (mx_type == "vector3") { - auto v = value->asA(); - f = v[0] + v[1] + v[2]; - } - else if (mx_type == "vector4") { - auto v = value->asA(); - f = v[0] + v[1] + v[2] + v[3]; - } - else { - BLI_assert_unreachable(); + switch (mx_type) { + case Type::Float: { + f = value->asA(); + break; + } + case Type::Vector2: { + auto v = value->asA(); + f = v[0] + v[1]; + break; + } + case Type::Vector3: { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + break; + } + case Type::Vector4: { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + break; + } + case Type::Color3: { + auto v = value->asA(); + f = v[0] + v[1] + v[2]; + break; + } + case Type::Color4: { + auto v = value->asA(); + f = v[0] + v[1] + v[2] + v[3]; + break; + } + default: + BLI_assert_unreachable(); } d.value = MaterialX::Value::createValue(f); } return d; } -NodeItem NodeItem::if_else(const std::string &condition, - const NodeItem &other, - const NodeItem &if_val, - const NodeItem &else_val) const -{ - if (condition == "<") { - return other.if_else(">", *this, else_val, if_val); - } - if (condition == "<=") { - return other.if_else(">=", *this, else_val, if_val); - } - if (condition == "!=") { - return if_else("==", other, else_val, if_val); - } - - NodeItem res = empty(); - if (type() != "float" || other.type() != "float") { - return res; - } - - auto val1 = if_val; - auto val2 = else_val; - std::string mx_type; - if (!adjust_types(val1, val2, mx_type)) { - return res; - } - - std::function func = nullptr; - std::string mx_category; - if (condition == ">") { - mx_category = "ifgreater"; - func = [](float a, float b) { return a > b; }; - } - else if (condition == ">=") { - mx_category = "ifgreatereq"; - func = [](float a, float b) { return a >= b; }; - } - else if (condition == "==") { - mx_category = "ifequal"; - func = [](float a, float b) { return a == b; }; - } - else { - BLI_assert_unreachable(); - } - - if (value && other.value) { - res = func(value->asA(), other.value->asA()) ? val1 : val2; - } - else { - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); - res.set_input("value1", *this); - res.set_input("value2", other); - res.set_input("in1", val1); - res.set_input("in2", val2); - } - - return res; -} - NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const { return (val(1.0f) - *this) * a + *this * b; @@ -374,247 +236,528 @@ NodeItem NodeItem::exp() const return arithmetic("exp", [](float a) { return std::expf(a); }); } -NodeItem NodeItem::to_color3() const +NodeItem NodeItem::convert(Type to_type) const { - std::string mx_type = type(); + Type from_type = type(); + if (from_type == to_type) { + return *this; + } + if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) { + return empty(); + } + + if (to_type == Type::Float) { + /* TODO: Convert to float, should be used */ + } + + /* Converting types which requires > 1 iteration */ + switch (from_type) { + case Type::Vector2: + switch (to_type) { + case Type::Vector4: + return convert(Type::Vector3).convert(Type::Vector4); + case Type::Color3: + return convert(Type::Vector3).convert(Type::Color3); + case Type::Color4: + return convert(Type::Vector3).convert(Type::Color3).convert(Type::Color4); + default: + break; + } + break; + case Type::Vector3: + switch (to_type) { + case Type::Color4: + return convert(Type::Color3).convert(Type::Color4); + default: + break; + } + break; + case Type::Vector4: + switch (to_type) { + case Type::Vector2: + return convert(Type::Vector3).convert(Type::Vector2); + case Type::Color3: + return convert(Type::Vector3).convert(Type::Color3); + default: + break; + } + break; + case Type::Color3: + switch (to_type) { + case Type::Vector2: + return convert(Type::Vector3).convert(Type::Vector2); + case Type::Vector4: + return convert(Type::Vector3).convert(Type::Vector4); + default: + break; + } + break; + case Type::Color4: + switch (to_type) { + case Type::Vector2: + return convert(Type::Vector4).convert(Type::Vector3).convert(Type::Vector2); + case Type::Vector3: + return convert(Type::Vector4).convert(Type::Vector3); + default: + break; + } + break; + default: + break; + } + + /* Converting 1 iteration types */ NodeItem res = empty(); if (value) { - MaterialX::Color3 c; - if (mx_type == "float") { - float v = value->asA(); - c = {v, v, v}; + switch (from_type) { + case Type::Float: { + float v = value->asA(); + switch (to_type) { + case Type::Vector2: + res.value = MaterialX::Value::createValue({v, v}); + break; + case Type::Vector3: + res.value = MaterialX::Value::createValue({v, v, v}); + break; + case Type::Vector4: + res.value = MaterialX::Value::createValue({v, v, v, 1.0f}); + break; + case Type::Color3: + res.value = MaterialX::Value::createValue({v, v, v}); + break; + case Type::Color4: + res.value = MaterialX::Value::createValue({v, v, v, 1.0f}); + break; + default: + BLI_assert_unreachable(); + } + break; + } + case Type::Vector2: { + auto v = value->asA(); + switch (to_type) { + case Type::Vector3: + res.value = MaterialX::Value::createValue({v[0], v[1], 0.0f}); + break; + default: + BLI_assert_unreachable(); + } + break; + } + case Type::Vector3: { + auto v = value->asA(); + switch (to_type) { + case Type::Vector2: + res.value = MaterialX::Value::createValue({v[0], v[1]}); + break; + case Type::Vector4: + res.value = MaterialX::Value::createValue( + {v[0], v[1], v[2], 0.0f}); + break; + case Type::Color3: + res.value = MaterialX::Value::createValue({v[0], v[1], v[2]}); + break; + default: + BLI_assert_unreachable(); + } + break; + } + case Type::Vector4: { + auto v = value->asA(); + switch (to_type) { + case Type::Vector3: + res.value = MaterialX::Value::createValue({v[0], v[1], v[2]}); + break; + case Type::Color4: + res.value = MaterialX::Value::createValue({v[0], v[1], v[2], v[3]}); + break; + default: + BLI_assert_unreachable(); + } + break; + } + case Type::Color3: { + auto v = value->asA(); + switch (to_type) { + case Type::Vector3: + res.value = MaterialX::Value::createValue({v[0], v[1], v[2]}); + break; + case Type::Color4: + res.value = MaterialX::Value::createValue({v[0], v[1], v[2], 1.0f}); + break; + default: + BLI_assert_unreachable(); + } + break; + } + case Type::Color4: { + auto v = value->asA(); + switch (to_type) { + case Type::Vector4: + res.value = MaterialX::Value::createValue( + {v[0], v[1], v[2], v[3]}); + break; + case Type::Color3: + res.value = MaterialX::Value::createValue({v[0], v[1], v[2]}); + break; + default: + BLI_assert_unreachable(); + } + break; + } + default: + BLI_assert_unreachable(); } - else if (mx_type == "color3") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (mx_type == "color4") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (mx_type == "vector3") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else if (mx_type == "vector4") { - auto v = value->asA(); - c = {v[0], v[1], v[2]}; - } - else { - return res; - } - res.value = MaterialX::Value::createValue(c); } - else if (node) { - if (mx_type != "color3") { - return res; - } - res.node = node; + else { + res.node = graph_->addNode("convert", MaterialX::EMPTY_STRING, type(to_type)); + res.set_input("in", *this); } return res; } -bool NodeItem::is_numeric() const +NodeItem NodeItem::if_else(CompareOp op, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const { - std::string t = type(); - return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4"); -} - -std::string NodeItem::type() const -{ - return value ? value->getTypeString() : node->getType(); -} - -NodeItem NodeItem::arithmetic(const std::string &mx_category, - std::function func) const -{ - if (!is_numeric()) { - return empty(); + switch (op) { + case CompareOp::Less: + return other.if_else(CompareOp::Greater, *this, else_val, if_val); + case CompareOp::LessEq: + return other.if_else(CompareOp::GreaterEq, *this, else_val, if_val); + case CompareOp::NotEq: + return if_else(CompareOp::Eq, other, else_val, if_val); + default: + break; } - std::string t = value ? value->getTypeString() : node->getType(); - NodeItem res(graph_); - if (value) { - if (t == "float") { - float v = value->asA(); - res.value = MaterialX::Value::createValue(func(v)); - } - else if (t == "color3") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2])}); - } - else if (t == "color4") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); - } - else if (t == "vector2") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); - } - else if (t == "vector3") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2])}); - } - else if (t == "vector4") { - auto v = value->asA(); - res.value = MaterialX::Value::createValue( - {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); - } - else { + NodeItem res = empty(); + if (type() != Type::Float || other.type() != Type::Float) { + return res; + } + + auto item1 = if_val; + auto item2 = else_val; + Type to_type = adjust_types(item1, item2); + if (to_type == Type::Empty) { + return res; + } + + std::function func = nullptr; + std::string mx_category; + switch (op) { + case CompareOp::Greater: + mx_category = "ifgreater"; + func = [](float a, float b) { return a > b; }; + break; + case CompareOp::GreaterEq: + mx_category = "ifgreatereq"; + func = [](float a, float b) { return a >= b; }; + break; + case CompareOp::Eq: + mx_category = "ifequal"; + func = [](float a, float b) { return a == b; }; + break; + default: BLI_assert_unreachable(); + } + + if (value && other.value) { + res = func(value->asA(), other.value->asA()) ? item1 : item2; + } + else { + res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(to_type)); + res.set_input("value1", *this); + res.set_input("value2", other); + res.set_input("in1", item1); + res.set_input("in2", item2); + } + + return res; +} + +NodeItem NodeItem::empty() const +{ + return NodeItem(graph_); +} + +NodeItem::Type NodeItem::type() const +{ + if (value) { + return type(value->getTypeString()); + } + if (node) { + return type(node->getType()); + } + return Type::Empty; +} + +void NodeItem::set_input(const std::string &name, + const NodeItem &item, + const std::string &output_name) +{ + if (item.value) { + Type item_type = item.type(); + std::string mx_type = type(item_type); + switch (item_type) { + case Type::String: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Integer: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Float: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Vector2: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Vector3: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Vector4: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Color3: + set_input(name, item.value->asA(), mx_type); + break; + case Type::Color4: + set_input(name, item.value->asA(), mx_type); + break; + default: + BLI_assert_unreachable(); + } + } + else if (item.node) { + node->setConnectedNode(name, item.node); + if (output_name != "") { + node->setConnectedOutput(name, item.node->getOutput(output_name)); } } else { - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t); + CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str()); + } +} + +void NodeItem::set_input(const std::string &name, + const NodeItem &item, + Type in_type, + const std::string &output_name) +{ + set_input(name, item.convert(in_type), output_name); +} + +void NodeItem::add_output(const std::string &name, Type out_type) +{ + node->addOutput(name, type(out_type)); +} + +NodeItem::Type NodeItem::type(const std::string &type_str) +{ + if (type_str == "string") { + return Type::String; + } + if (type_str == "integer") { + return Type::Integer; + } + if (type_str == "float") { + return Type::Float; + } + if (type_str == "vector2") { + return Type::Vector2; + } + if (type_str == "vector3") { + return Type::Vector3; + } + if (type_str == "vector4") { + return Type::Vector4; + } + if (type_str == "color3") { + return Type::Color3; + } + if (type_str == "color4") { + return Type::Color4; + } + return Type::Other; +} + +std::string NodeItem::type(Type type) +{ + switch (type) { + case Type::String: + return "string"; + case Type::Integer: + return "integer"; + case Type::Float: + return "float"; + case Type::Vector2: + return "vector2"; + case Type::Vector3: + return "vector3"; + case Type::Vector4: + return "vector4"; + case Type::Color3: + return "color3"; + case Type::Color4: + return "color4"; + default: + break; + } + return ""; +} + +bool NodeItem::is_arithmetic(Type type) +{ + return type >= Type::Float; +} + +NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2) +{ + Type t1 = item1.type(); + Type t2 = item2.type(); + if (t1 == t2) { + return t1; + } + if (!is_arithmetic(t1) || !is_arithmetic(t2)) { + return Type::Empty; + } + if (t1 < t2) { + item1 = item1.convert(t2); + return t2; + } + else { + item2 = item2.convert(t1); + return t1; + } +} + +bool NodeItem::is_arithmetic() const +{ + return is_arithmetic(type()); +} + +NodeItem NodeItem::arithmetic(const std::string &category, std::function func) const +{ + NodeItem res = empty(); + Type type = this->type(); + if (!is_arithmetic(type)) { + return res; + } + + if (value) { + switch (type) { + case Type::Float: { + float v = value->asA(); + res.value = MaterialX::Value::createValue(func(v)); + break; + } + case Type::Color3: { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + break; + } + case Type::Color4: { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + break; + } + case Type::Vector2: { + auto v = value->asA(); + res.value = MaterialX::Value::createValue({func(v[0]), func(v[1])}); + } + case Type::Vector3: { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2])}); + break; + } + case Type::Vector4: { + auto v = value->asA(); + res.value = MaterialX::Value::createValue( + {func(v[0]), func(v[1]), func(v[2]), func(v[3])}); + break; + } + default: + BLI_assert_unreachable(); + } + } + else { + /* TODO: Some of math functions (sin, cos, ...) doesn't work with Color types, + * we have to convert to Vector */ + res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, this->type(type)); res.set_input("in", *this); } return res; } NodeItem NodeItem::arithmetic(const NodeItem &other, - const std::string &mx_category, + const std::string &category, std::function func) const { NodeItem res = empty(); - if (!is_numeric() || !other.is_numeric()) { + NodeItem item1 = *this; + NodeItem item2 = other; + Type to_type = adjust_types(item1, item2); + if (to_type == Type::Empty) { return res; } - std::string mx_type; if (value && other.value) { - auto val1 = value; - auto val2 = other.value; - if (!adjust_types(val1, val2, mx_type)) { - return res; - } - - if (mx_type == "float") { - float v1 = val1->asA(); - float v2 = val2->asA(); - res.value = MaterialX::Value::createValue(func(v1, v2)); - } - else if (mx_type == "color3") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); - } - else if (mx_type == "color4") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); - } - else if (mx_type == "vector2") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1])}); - } - else if (mx_type == "vector3") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); - } - else if (mx_type == "vector4") { - auto v1 = val1->asA(); - auto v2 = val2->asA(); - res.value = MaterialX::Value::createValue( - {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); - } - else { - BLI_assert_unreachable(); + switch (to_type) { + case Type::Float: { + float v1 = item1.value->asA(); + float v2 = item2.value->asA(); + res.value = MaterialX::Value::createValue(func(v1, v2)); + break; + } + case Type::Color3: { + auto v1 = item1.value->asA(); + auto v2 = item2.value->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + break; + } + case Type::Color4: { + auto v1 = item1.value->asA(); + auto v2 = item2.value->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + break; + } + case Type::Vector2: { + auto v1 = item1.value->asA(); + auto v2 = item2.value->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1])}); + break; + } + case Type::Vector3: { + auto v1 = item1.value->asA(); + auto v2 = item2.value->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])}); + break; + } + case Type::Vector4: { + auto v1 = item1.value->asA(); + auto v2 = item2.value->asA(); + res.value = MaterialX::Value::createValue( + {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])}); + break; + } + default: + BLI_assert_unreachable(); } } else { - auto val1 = *this; - auto val2 = other; - if (!adjust_types(val1, val2, mx_type)) { - return res; - } - - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); - res.set_input("in1", val1); - res.set_input("in2", val2); + res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type(to_type)); + res.set_input("in1", item1); + res.set_input("in2", item2); } return res; } -MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string mx_type) -{ - if (mx_type == "float") { - return MaterialX::Value::createValue(v); - } - if (mx_type == "color3") { - return MaterialX::Value::createValue({v, v, v}); - } - if (mx_type == "color4") { - return MaterialX::Value::createValue({v, v, v, 1.0f}); - } - if (mx_type == "vector2") { - return MaterialX::Value::createValue({v, v}); - } - if (mx_type == "vector3") { - return MaterialX::Value::createValue({v, v, v}); - } - if (mx_type == "vector4") { - return MaterialX::Value::createValue({v, v, v, 1.0f}); - } - - BLI_assert_unreachable(); - return nullptr; -} - -bool NodeItem::adjust_types(MaterialX::ValuePtr &val1, - MaterialX::ValuePtr &val2, - std::string &mx_type) -{ - std::string t1 = val1->getTypeString(); - std::string t2 = val2->getTypeString(); - if (t1 != t2) { - if (t1 == "float") { - val1 = float_to_type(val1->asA(), t2); - mx_type = t2; - } - else if (t2 == "float") { - val2 = float_to_type(val2->asA(), t1); - mx_type = t1; - } - else { - return false; - } - } - else { - mx_type = t1; - } - return true; -} - -bool NodeItem::adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type) -{ - std::string t1 = val1.type(); - std::string t2 = val2.type(); - if (t1 != t2) { - if (val1.value && t1 == "float") { - val1.value = float_to_type(val1.value->asA(), t2); - mx_type = t2; - } - else if (val2.value && t2 == "float") { - val2.value = float_to_type(val2.value->asA(), t1); - mx_type = t1; - } - else { - return false; - } - } - else { - mx_type = t1; - } - return true; -} - } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 2f746cda36b..466ce42b954 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -9,6 +9,21 @@ namespace blender::nodes::materialx { class NodeItem { + public: + enum class Type { + Empty = 0, + Other, /* For MaterialX types like: surfaceshader, bsdf, edf, ...*/ + String, + Integer, + Float, + Vector2, + Vector3, + Vector4, + Color3, + Color4 + }; + enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq }; + public: MaterialX::ValuePtr value; MaterialX::NodePtr node; @@ -20,20 +35,7 @@ class NodeItem { NodeItem(MaterialX::GraphElement *graph); ~NodeItem() = default; - NodeItem empty() const; - template NodeItem val(const T &data) const; - - template - void set_input(const std::string &name, const T &value, const std::string &mx_type); - void set_input(const std::string &name, - const NodeItem &item, - const std::string &output_name = ""); - void set_input(const std::string &name, const MaterialX::ValuePtr value); - void set_input(const std::string &name, - const MaterialX::NodePtr node, - const std::string &output_name = ""); - void add_output(const std::string &name, const std::string &mx_type); - + /* Operators */ operator bool() const; NodeItem operator+(const NodeItem &other) const; NodeItem operator-(const NodeItem &other) const; @@ -45,16 +47,13 @@ class NodeItem { bool operator==(const NodeItem &other) const; bool operator!=(const NodeItem &other) const; + /* Math functions */ NodeItem abs() const; NodeItem floor() const; NodeItem ceil() const; NodeItem min(const NodeItem &other) const; NodeItem max(const NodeItem &other) const; NodeItem dotproduct(const NodeItem &other) const; - NodeItem if_else(const std::string &condition, - const NodeItem &other, - const NodeItem &if_val, - const NodeItem &else_val) const; NodeItem blend(const NodeItem &a, const NodeItem &b) 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; @@ -72,22 +71,40 @@ class NodeItem { NodeItem sqrt() const; NodeItem sign() const; NodeItem exp() const; + NodeItem convert(Type to_type) const; + NodeItem if_else(CompareOp op, + const NodeItem &other, + const NodeItem &if_val, + const NodeItem &else_val) const; - NodeItem to_color3() const; - bool is_numeric() const; - std::string type() const; + /* Useful functions */ + NodeItem empty() const; + template NodeItem val(const T &data) const; + Type type() const; + + /* Functions to set input and output */ + template + void set_input(const std::string &in_name, const T &value, const std::string &in_type); + void set_input(const std::string &in_name, + const NodeItem &item, + const std::string &out_name = ""); + void set_input(const std::string &in_name, + const NodeItem &item, + Type in_type, + const std::string &out_name = ""); + void add_output(const std::string &in_name, Type out_type); private: - NodeItem arithmetic(const std::string &mx_category, std::function func) const; + static Type type(const std::string &type_str); + static std::string type(Type type); + static bool is_arithmetic(Type type); + static Type adjust_types(NodeItem &item1, NodeItem &item2); + + bool is_arithmetic() const; + NodeItem arithmetic(const std::string &category, std::function func) const; NodeItem arithmetic(const NodeItem &other, - const std::string &mx_category, + const std::string &category, std::function func) const; - static MaterialX::ValuePtr float_to_type(float v, std::string mx_type); - /* Functions for adjusting values to make equal types */ - static bool adjust_types(MaterialX::ValuePtr &val1, - MaterialX::ValuePtr &val2, - std::string &mx_type); - static bool adjust_types(NodeItem &val1, NodeItem &val2, std::string &mx_type); }; template NodeItem NodeItem::val(const T &data) const @@ -98,9 +115,9 @@ template NodeItem NodeItem::val(const T &data) const } template -void NodeItem::set_input(const std::string &name, const T &value, const std::string &mx_type) +void NodeItem::set_input(const std::string &in_name, const T &value, const std::string &in_type) { - node->setInputValue(name, value, mx_type); + node->setInputValue(in_name, value, in_type); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 0b7c6e82ad6..187590c7332 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -14,7 +14,11 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph, const Material *material, const bNode *node, const bNodeSocket *socket_out) - : graph_(graph), depsgraph_(depsgraph), material_(material), node_(node), socket_out_(socket_out) + : graph_(graph), + depsgraph_(depsgraph), + material_(material), + node_(node), + socket_out_(socket_out) { } @@ -74,17 +78,20 @@ NodeItem NodeParser::get_input_default(const bNodeSocket &socket) case SOCK_FLOAT: { float v = socket.default_value_typed()->value; res.value = MaterialX::Value::createValue(v); - } break; + break; + } case SOCK_VECTOR: { const float *v = socket.default_value_typed()->value; res.value = MaterialX::Value::createValue( MaterialX::Vector3(v[0], v[1], v[2])); - } break; + break; + } case SOCK_RGBA: { const float *v = socket.default_value_typed()->value; res.value = MaterialX::Value::createValue( MaterialX::Color4(v[0], v[1], v[2], v[3])); - } break; + break; + } default: { CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type); } @@ -115,7 +122,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) /* Checking if node was already computed */ res.node = graph_->getNode(node_name(from_node, link->fromsock)); if (res.node) { - return res; + return res; } /* Computing from_node with required NodeParser object */ diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index 5b5d9d0b7c6..92fd81dbbe2 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -37,7 +37,8 @@ NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name) NodeItem OutputMaterialNodeParser::compute_default() { NodeItem surface = create_node("standard_surface", "surfaceshader"); - surface.set_input("base_color", value(MaterialX::Color3(material_->r, material_->g, material_->b))); + surface.set_input("base_color", + value(MaterialX::Color3(material_->r, material_->g, material_->b))); surface.set_input("diffuse_roughness", value(material_->roughness)); if (material_->metallic > 0.0f) { surface.set_input("metalness", value(material_->metallic)); diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index 63266bd5081..8325bb0e06e 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -8,23 +8,20 @@ namespace blender::nodes::materialx { NodeItem TexCheckerNodeParser::compute() { - NodeItem scale = get_input_value("Scale"); + NodeItem vector = get_input_link("Vector"); NodeItem color1 = get_input_value("Color1"); NodeItem color2 = get_input_value("Color2"); + NodeItem scale = get_input_value("Scale"); - if (scale.value && scale.type() == "float") { - float v = scale.value->asA(); - scale = value(MaterialX::Vector2(v, v)); + if (!vector) { + vector = create_node("texcoord", "vector2"); } - - NodeItem texcoord = create_node("texcoord", "vector2"); - NodeItem place2d = create_node("place2d", "vector2"); - place2d.set_input("texcoord", texcoord * scale); + vector = vector * scale; NodeItem separate = create_node("separate2", "multioutput"); - separate.set_input("in", place2d); - separate.add_output("outx", "float"); - separate.add_output("outy", "float"); + separate.set_input("in", vector, NodeItem::Type::Vector2); + separate.add_output("outx", NodeItem::Type::Float); + separate.add_output("outy", NodeItem::Type::Float); NodeItem modulo_x = create_node("modulo", "float"); modulo_x.set_input("in1", separate, "outx"); @@ -34,12 +31,12 @@ NodeItem TexCheckerNodeParser::compute() modulo_y.set_input("in1", separate, "outy"); modulo_y.set_input("in2", value(2.0f)); - NodeItem ifequal = - (modulo_x.floor() + modulo_y.floor()).if_else("==", value(1.0f), value(0.0f), value(1.0f)); + NodeItem ifequal = (modulo_x.floor() + modulo_y.floor()) + .if_else(NodeItem::CompareOp::Eq, value(1.0f), value(0.0f), value(1.0f)); NodeItem res = create_node("mix", "color3"); - res.set_input("bg", color1.to_color3()); - res.set_input("fg", color2.to_color3()); + res.set_input("bg", color1, NodeItem::Type::Color3); + res.set_input("fg", color2, NodeItem::Type::Color3); res.set_input("mix", ifequal); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc index d3a016c6320..2136f8abd06 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc @@ -12,14 +12,15 @@ NodeItem TexNoiseNodeParser::compute() NodeItem detail = get_input_value("Detail"); NodeItem lacunarity = get_input_value("Lacunarity"); - if (detail.value && detail.type() == "float") { + if (detail.value && detail.type() == NodeItem::Type::Float) { detail = value(int(detail.value->asA())); } - NodeItem texcoord = create_node("position", "vector3"); + NodeItem position = create_node("position", "vector3"); + position = position * scale; NodeItem res = create_node("fractal3d", "color3"); - res.set_input("position", texcoord * scale); + res.set_input("position", position, NodeItem::Type::Vector3); res.set_input("octaves", detail); res.set_input("lacunarity", lacunarity); return res; -- 2.30.2 From bbc3b2614af93bdc4ee3d481ba72b26309caaf30 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Wed, 6 Sep 2023 10:37:15 +0200 Subject: [PATCH 11/40] MaterialX: add support for nodes ### Purpose Add support for more nodes ### Technical steps Added support for: * Separate, Combine XYZ * Separate, Combine Color * Vector Math (not all operations) * Hue/Saturation/Value * Normal Map * Brightness/Contrast Implemented `NodeItem::extract()` Fixed BSDF Principled node Pull Request: https://projects.blender.org/DagerD/blender/pulls/11 --- source/blender/nodes/shader/CMakeLists.txt | 14 +- .../shader/materialx/nodes/brightness.cc | 19 +++ .../shader/materialx/nodes/bsdf_principled.cc | 98 +++++--------- .../nodes/shader/materialx/nodes/huesatval.cc | 33 +++++ .../nodes/shader/materialx/nodes/node_item.cc | 11 +- .../nodes/shader/materialx/nodes/node_item.h | 1 + .../shader/materialx/nodes/node_parser.cc | 8 ++ .../shader/materialx/nodes/node_parser.h | 9 ++ .../shader/materialx/nodes/normal_map.cc | 40 ++++++ .../shader/materialx/nodes/sepcomb_color.cc | 72 +++++++++++ .../shader/materialx/nodes/sepcomb_xyz.cc | 28 ++++ .../shader/materialx/nodes/vector_math.cc | 122 ++++++++++++++++++ 12 files changed, 383 insertions(+), 72 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/brightness.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/huesatval.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/normal_map.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/vector_math.cc diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 114ab576101..9a3b77502fb 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 00000000000..026621ea427 --- /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 a8829ddf92f..5abd13ddaab 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 00000000000..8d3af670a29 --- /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 5e6df0555fc..1b1801e741c 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 466ce42b954..6e9e011ad2f 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 187590c7332..f3fa66be0ac 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 bb9986896d9..ebd9ec05c7d 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 00000000000..b7cc0ff9a20 --- /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 00000000000..02f7d60e1bf --- /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 00000000000..104130d840b --- /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 00000000000..db8a165a626 --- /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 -- 2.30.2 From e34ad4750478102017bf63ea99817851c05da689 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Wed, 6 Sep 2023 16:01:16 +0200 Subject: [PATCH 12/40] MaterialX: Move NodeItem::Type argument from setters to getters ### Purpose Move NodeItem::Type argument from setters to getters ### Technical steps Moved NodeItem::Type argument from setters to getters Pull Request:https://projects.blender.org/DagerD/blender/pulls/12 --- .../shader/materialx/nodes/brightness.cc | 6 +-- .../shader/materialx/nodes/bsdf_principled.cc | 52 +++++++++---------- .../nodes/shader/materialx/nodes/huesatval.cc | 12 ++--- .../nodes/shader/materialx/nodes/invert.cc | 4 +- .../nodes/shader/materialx/nodes/math.cc | 6 +-- .../nodes/shader/materialx/nodes/node_item.cc | 8 --- .../nodes/shader/materialx/nodes/node_item.h | 4 -- .../shader/materialx/nodes/node_parser.cc | 12 ++--- .../shader/materialx/nodes/node_parser.h | 8 +-- .../shader/materialx/nodes/normal_map.cc | 6 +-- .../shader/materialx/nodes/sepcomb_color.cc | 8 +-- .../shader/materialx/nodes/sepcomb_xyz.cc | 8 +-- .../shader/materialx/nodes/tex_checker.cc | 12 ++--- .../nodes/shader/materialx/nodes/tex_noise.cc | 8 +-- .../shader/materialx/nodes/vector_math.cc | 6 +-- 15 files changed, 74 insertions(+), 86 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/brightness.cc b/source/blender/nodes/shader/materialx/nodes/brightness.cc index 026621ea427..7c3261c9f2b 100644 --- a/source/blender/nodes/shader/materialx/nodes/brightness.cc +++ b/source/blender/nodes/shader/materialx/nodes/brightness.cc @@ -8,9 +8,9 @@ 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"); + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem bright = get_input_value("Bright", NodeItem::Type::Float); + NodeItem contrast = get_input_value("Contrast", NodeItem::Type::Float); /* 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)); diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 5abd13ddaab..41e93336471 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -8,38 +8,36 @@ namespace blender::nodes::materialx { NodeItem BSDFPrincipledNodeParser::compute() { - /* Getting required inputs - * Note: if some inputs are not needed they won't be taken */ - NodeItem base_color = get_input_value("Base Color"); + NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3); - NodeItem subsurface = get_input_value("Subsurface"); - NodeItem subsurface_radius = get_input_value("Subsurface Radius"); - NodeItem subsurface_color = get_input_value("Subsurface Color"); + NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float); + NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3); + NodeItem subsurface_color = get_input_value("Subsurface Color", NodeItem::Type::Color3); - NodeItem metallic = get_input_value("Metallic"); - NodeItem specular = get_input_value("Specular"); + NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float); + NodeItem specular = get_input_value("Specular", NodeItem::Type::Float); // NodeItem specular_tint = get_input_value("Specular Tint"); - NodeItem roughness = get_input_value("Roughness"); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); /* TODO: use Specular Tint input */ - NodeItem anisotropic = get_input_value("Anisotropic"); - NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation"); + NodeItem anisotropic = get_input_value("Anisotropic", NodeItem::Type::Float); + NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation", NodeItem::Type::Float); // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) - NodeItem sheen = get_input_value("Sheen"); + NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float); // sheen_tint = get_input_value("Sheen Tint"); - NodeItem clearcoat = get_input_value("Clearcoat"); - NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness"); + NodeItem clearcoat = get_input_value("Clearcoat", NodeItem::Type::Float); + NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness", NodeItem::Type::Float); - NodeItem ior = get_input_value("IOR"); + NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); - NodeItem transmission = get_input_value("Transmission"); + NodeItem transmission = get_input_value("Transmission", NodeItem::Type::Float); - NodeItem emission = get_input_value("Emission"); - NodeItem emission_strength = get_input_value("Emission Strength"); + NodeItem emission = get_input_value("Emission", NodeItem::Type::Color3); + NodeItem emission_strength = get_input_value("Emission Strength", NodeItem::Type::Float); - NodeItem alpha = get_input_value("Alpha"); + NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float); // transparency = 1.0 - alpha NodeItem normal = get_input_link("Normal"); @@ -49,7 +47,7 @@ NodeItem BSDFPrincipledNodeParser::compute() /* Creating standard_surface */ NodeItem res = create_node("standard_surface", "surfaceshader"); res.set_input("base", 1.0, "float"); - res.set_input("base_color", base_color, NodeItem::Type::Color3); + res.set_input("base_color", base_color); res.set_input("diffuse_roughness", roughness); if (normal) { res.set_input("normal", normal); @@ -60,27 +58,27 @@ NodeItem BSDFPrincipledNodeParser::compute() res.set_input("metalness", metallic); res.set_input("specular", specular); - res.set_input("specular_color", base_color, NodeItem::Type::Color3); + res.set_input("specular_color", base_color); 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); res.set_input("transmission", transmission); - res.set_input("transmission_color", base_color, NodeItem::Type::Color3); + res.set_input("transmission_color", base_color); res.set_input("transmission_extra_roughness", roughness); res.set_input("subsurface", subsurface); - res.set_input("subsurface_color", subsurface_color, NodeItem::Type::Color3); - res.set_input("subsurface_radius", subsurface_radius, NodeItem::Type::Color3); + res.set_input("subsurface_color", subsurface_color); + res.set_input("subsurface_radius", subsurface_radius); res.set_input("subsurface_anisotropy", anisotropic); res.set_input("sheen", sheen); - res.set_input("sheen_color", base_color, NodeItem::Type::Color3); + res.set_input("sheen_color", base_color); res.set_input("sheen_roughness", roughness); res.set_input("coat", clearcoat); - res.set_input("coat_color", base_color, NodeItem::Type::Color3); + res.set_input("coat_color", base_color); res.set_input("coat_roughness", clearcoat_roughness); res.set_input("coat_IOR", ior); res.set_input("coat_anisotropy", anisotropic); @@ -90,7 +88,7 @@ NodeItem BSDFPrincipledNodeParser::compute() } res.set_input("emission", emission_strength); - res.set_input("emission_color", emission, NodeItem::Type::Color3); + res.set_input("emission_color", emission); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/huesatval.cc b/source/blender/nodes/shader/materialx/nodes/huesatval.cc index 8d3af670a29..05723f49a3f 100644 --- a/source/blender/nodes/shader/materialx/nodes/huesatval.cc +++ b/source/blender/nodes/shader/materialx/nodes/huesatval.cc @@ -10,11 +10,11 @@ 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"); + NodeItem hue = get_input_value("Hue", NodeItem::Type::Float); + NodeItem saturation = get_input_value("Saturation", NodeItem::Type::Float); + NodeItem val = get_input_value("Value", NodeItem::Type::Float); + NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); /* Modifier to follow Cycles result */ hue = hue - value(0.5f); @@ -25,7 +25,7 @@ NodeItem HueSatValNodeParser::compute() combine.set_input("in3", val); NodeItem res = create_node("hsvadjust", "color3"); - res.set_input("in", color, NodeItem::Type::Color3); + res.set_input("in", color); res.set_input("amount", combine); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/invert.cc b/source/blender/nodes/shader/materialx/nodes/invert.cc index b6ca706330f..47ef4857899 100644 --- a/source/blender/nodes/shader/materialx/nodes/invert.cc +++ b/source/blender/nodes/shader/materialx/nodes/invert.cc @@ -8,8 +8,8 @@ namespace blender::nodes::materialx { NodeItem InvertNodeParser::compute() { - NodeItem fac = get_input_value("Fac"); - NodeItem color = get_input_value("Color"); + NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); return fac.blend(color, fac.val(1.0f) - color); } diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index 598c80a2fae..c974f9d46a3 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -14,7 +14,7 @@ NodeItem MathNodeParser::compute() NodeItem res = empty(); /* Single operand operations */ - NodeItem x = get_input_value(0); + NodeItem x = get_input_value(0, NodeItem::Type::Empty); switch (op) { case NODE_MATH_SINE: res = x.sin(); @@ -82,7 +82,7 @@ NodeItem MathNodeParser::compute() default: { /* 2-operand operations */ - NodeItem y = get_input_value(1); + NodeItem y = get_input_value(1, NodeItem::Type::Empty); switch (op) { case NODE_MATH_ADD: res = x + y; @@ -132,7 +132,7 @@ NodeItem MathNodeParser::compute() default: { /* 3-operand operations */ - NodeItem z = get_input_value(2); + NodeItem z = get_input_value(2, NodeItem::Type::Empty); switch (op) { case NODE_MATH_WRAP: CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 1b1801e741c..7801d540913 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -549,14 +549,6 @@ void NodeItem::set_input(const std::string &name, } } -void NodeItem::set_input(const std::string &name, - const NodeItem &item, - Type in_type, - const std::string &output_name) -{ - set_input(name, item.convert(in_type), output_name); -} - void NodeItem::add_output(const std::string &name, Type out_type) { node->addOutput(name, type(out_type)); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 6e9e011ad2f..19e29ef1854 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -89,10 +89,6 @@ class NodeItem { void set_input(const std::string &in_name, const NodeItem &item, const std::string &out_name = ""); - void set_input(const std::string &in_name, - const NodeItem &item, - Type in_type, - const std::string &out_name = ""); void add_output(const std::string &in_name, Type out_type); private: diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index f3fa66be0ac..ec3462efb80 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -56,14 +56,14 @@ NodeItem NodeParser::get_input_link(int index) return get_input_link(node_->input_socket(index)); } -NodeItem NodeParser::get_input_value(const std::string &name) +NodeItem NodeParser::get_input_value(const std::string &name, const NodeItem::Type type) { - return get_input_value(node_->input_by_identifier(name)); + return get_input_value(node_->input_by_identifier(name), type); } -NodeItem NodeParser::get_input_value(int index) +NodeItem NodeParser::get_input_value(int index, const NodeItem::Type type) { - return get_input_value(node_->input_socket(index)); + return get_input_value(node_->input_socket(index), type); } NodeItem NodeParser::empty() const @@ -159,13 +159,13 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) return res; } -NodeItem NodeParser::get_input_value(const bNodeSocket &socket) +NodeItem NodeParser::get_input_value(const bNodeSocket &socket, const NodeItem::Type type) { NodeItem res = get_input_link(socket); if (!res) { res = get_input_default(socket); } - return res; + return type == NodeItem::Type::Empty ? res : res.convert(type); } NodeItem NodeParser::compute_full() diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index ebd9ec05c7d..15243b74f99 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -37,15 +37,17 @@ class NodeParser { NodeItem get_input_default(int index); NodeItem get_input_link(const std::string &name); NodeItem get_input_link(int index); - NodeItem get_input_value(const std::string &name); - NodeItem get_input_value(int index); + NodeItem get_input_value(const std::string &name, + const NodeItem::Type type); + NodeItem get_input_value(int index, const NodeItem::Type type); NodeItem empty() const; template NodeItem value(const T &data) const; private: NodeItem get_input_default(const bNodeSocket &socket); NodeItem get_input_link(const bNodeSocket &socket); - NodeItem get_input_value(const bNodeSocket &socket); + NodeItem get_input_value(const bNodeSocket &socket, + const NodeItem::Type type); NodeItem compute_full(); }; diff --git a/source/blender/nodes/shader/materialx/nodes/normal_map.cc b/source/blender/nodes/shader/materialx/nodes/normal_map.cc index b7cc0ff9a20..8145a3444ac 100644 --- a/source/blender/nodes/shader/materialx/nodes/normal_map.cc +++ b/source/blender/nodes/shader/materialx/nodes/normal_map.cc @@ -11,11 +11,11 @@ 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 color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); NodeItem res = create_node("normalmap", "vector3"); - res.set_input("in", color, NodeItem::Type::Color3); + res.set_input("in", color); res.set_input("scale", strength); switch (normal_map_node->space) { diff --git a/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc b/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc index 02f7d60e1bf..7867808285d 100644 --- a/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc +++ b/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc @@ -10,7 +10,7 @@ namespace blender::nodes::materialx { NodeItem SeparateColorNodeParser::compute() { int mode = static_cast(node_->storage)->mode; - NodeItem color = get_input_value("Color"); + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem convert = empty(); @@ -39,9 +39,9 @@ NodeItem SeparateColorNodeParser::compute() 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 red = get_input_value("Red", NodeItem::Type::Float); + NodeItem green = get_input_value("Green", NodeItem::Type::Float); + NodeItem blue = get_input_value("Blue", NodeItem::Type::Float); NodeItem convert = empty(); NodeItem combine = create_node("combine3", "color3"); diff --git a/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc b/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc index 104130d840b..1143a97511d 100644 --- a/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc +++ b/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc @@ -8,16 +8,16 @@ namespace blender::nodes::materialx { NodeItem SeparateXYZNodeParser::compute() { - NodeItem vector = get_input_value("Vector"); + 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); } NodeItem CombineXYZNodeParser::compute() { - NodeItem x = get_input_value("X"); - NodeItem y = get_input_value("Y"); - NodeItem z = get_input_value("Z"); + NodeItem x = get_input_value("X", NodeItem::Type::Float); + NodeItem y = get_input_value("Y", NodeItem::Type::Float); + NodeItem z = get_input_value("Z", NodeItem::Type::Float); NodeItem res = create_node("combine3", "vector3"); res.set_input("in1", x); res.set_input("in2", y); diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index 8325bb0e06e..7cf1d8ee52a 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -9,9 +9,9 @@ namespace blender::nodes::materialx { NodeItem TexCheckerNodeParser::compute() { NodeItem vector = get_input_link("Vector"); - NodeItem color1 = get_input_value("Color1"); - NodeItem color2 = get_input_value("Color2"); - NodeItem scale = get_input_value("Scale"); + NodeItem color1 = get_input_value("Color1", NodeItem::Type::Color3); + NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3); + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); if (!vector) { vector = create_node("texcoord", "vector2"); @@ -19,7 +19,7 @@ NodeItem TexCheckerNodeParser::compute() vector = vector * scale; NodeItem separate = create_node("separate2", "multioutput"); - separate.set_input("in", vector, NodeItem::Type::Vector2); + separate.set_input("in", vector); separate.add_output("outx", NodeItem::Type::Float); separate.add_output("outy", NodeItem::Type::Float); @@ -35,8 +35,8 @@ NodeItem TexCheckerNodeParser::compute() .if_else(NodeItem::CompareOp::Eq, value(1.0f), value(0.0f), value(1.0f)); NodeItem res = create_node("mix", "color3"); - res.set_input("bg", color1, NodeItem::Type::Color3); - res.set_input("fg", color2, NodeItem::Type::Color3); + res.set_input("bg", color1); + res.set_input("fg", color2); res.set_input("mix", ifequal); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc index 2136f8abd06..60631acb4ff 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc @@ -8,9 +8,9 @@ namespace blender::nodes::materialx { NodeItem TexNoiseNodeParser::compute() { - NodeItem scale = get_input_value("Scale"); - NodeItem detail = get_input_value("Detail"); - NodeItem lacunarity = get_input_value("Lacunarity"); + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); + NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); + NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); if (detail.value && detail.type() == NodeItem::Type::Float) { detail = value(int(detail.value->asA())); @@ -20,7 +20,7 @@ NodeItem TexNoiseNodeParser::compute() position = position * scale; NodeItem res = create_node("fractal3d", "color3"); - res.set_input("position", position, NodeItem::Type::Vector3); + res.set_input("position", position); res.set_input("octaves", detail); res.set_input("lacunarity", lacunarity); return res; diff --git a/source/blender/nodes/shader/materialx/nodes/vector_math.cc b/source/blender/nodes/shader/materialx/nodes/vector_math.cc index db8a165a626..df476460969 100644 --- a/source/blender/nodes/shader/materialx/nodes/vector_math.cc +++ b/source/blender/nodes/shader/materialx/nodes/vector_math.cc @@ -14,7 +14,7 @@ NodeItem VectorMathNodeParser::compute() NodeItem res = empty(); /* Single operand operations */ - NodeItem x = get_input_value(0); + NodeItem x = get_input_value(0, NodeItem::Type::Empty); switch (op) { case NODE_VECTOR_MATH_SINE: res = x.sin(); @@ -46,7 +46,7 @@ NodeItem VectorMathNodeParser::compute() default: { /* 2-operand operations */ - NodeItem y = get_input_value(1); + NodeItem y = get_input_value(1, NodeItem::Type::Empty); switch (op) { case NODE_VECTOR_MATH_ADD: res = x + y; @@ -93,7 +93,7 @@ NodeItem VectorMathNodeParser::compute() default: { /* 3-operand operations */ - NodeItem z = get_input_value(2); + NodeItem z = get_input_value(2, NodeItem::Type::Empty); switch (op) { case NODE_VECTOR_MATH_MULTIPLY_ADD: res = x * y + z; -- 2.30.2 From a464b5854e3be0bbcc7e96b9d415b4851c61fc83 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 7 Sep 2023 11:22:22 +0200 Subject: [PATCH 13/40] Implement export of Shader BSDF nodes ### Purpose Shader nodes has to be implemented. Adjust parsing system for export shaders. ### Technical steps 1. Added supported shader types to `NodeItem::Type`, added `Type::Any`, added comments. 2. Created `class ShaderNodeParser` special for parse shaders. 3. Added type conversion to `get_input_link()` and `get_input_default()`. 4. Added file templates for export new shaders. Implemented `AddShader`, `BSDFDiffuse`, `Emission`, `MixShader`. 5. Improved TexChecker using arithmetic functions. ### Notes Other shaders aren't implemented, added TODOs. They'll be implemented in next PRs. Pull Request: https://projects.blender.org/DagerD/blender/pulls/13 --- source/blender/nodes/shader/CMakeLists.txt | 12 ++ .../nodes/shader/materialx/material.cc | 6 +- .../blender/nodes/shader/materialx/material.h | 4 +- .../shader/materialx/nodes/add_shader.cc | 42 ++++ .../shader/materialx/nodes/bsdf_diffuse.cc | 28 +++ .../shader/materialx/nodes/bsdf_glass.cc | 15 ++ .../shader/materialx/nodes/bsdf_glossy.cc | 15 ++ .../shader/materialx/nodes/bsdf_principled.cc | 11 +- .../shader/materialx/nodes/bsdf_refraction.cc | 15 ++ .../shader/materialx/nodes/bsdf_sheen.cc | 15 ++ .../nodes/shader/materialx/nodes/bsdf_toon.cc | 15 ++ .../materialx/nodes/bsdf_translucent.cc | 15 ++ .../materialx/nodes/bsdf_transparent.cc | 15 ++ .../nodes/shader/materialx/nodes/emission.cc | 23 +++ .../nodes/shader/materialx/nodes/math.cc | 6 +- .../shader/materialx/nodes/mix_shader.cc | 46 +++++ .../nodes/shader/materialx/nodes/node_item.cc | 183 +++++++++++------ .../nodes/shader/materialx/nodes/node_item.h | 27 ++- .../shader/materialx/nodes/node_parser.cc | 187 ++++++++++++++---- .../shader/materialx/nodes/node_parser.h | 100 +++++++--- .../shader/materialx/nodes/output_material.cc | 28 ++- .../shader/materialx/nodes/output_material.h | 8 +- .../materialx/nodes/subsurface_scattering.cc | 15 ++ .../shader/materialx/nodes/tex_checker.cc | 29 +-- .../shader/materialx/nodes/vector_math.cc | 6 +- 25 files changed, 685 insertions(+), 181 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/add_shader.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/emission.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/mix_shader.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 9a3b77502fb..1d75ad77a3d 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -147,18 +147,30 @@ set(LIB if(WITH_MATERIALX) list(APPEND SRC materialx/material.cc + materialx/nodes/add_shader.cc materialx/nodes/brightness.cc + materialx/nodes/bsdf_diffuse.cc + materialx/nodes/bsdf_glass.cc + materialx/nodes/bsdf_glossy.cc materialx/nodes/bsdf_principled.cc + materialx/nodes/bsdf_refraction.cc + materialx/nodes/bsdf_sheen.cc + materialx/nodes/bsdf_toon.cc + materialx/nodes/bsdf_translucent.cc + materialx/nodes/bsdf_transparent.cc + materialx/nodes/emission.cc materialx/nodes/huesatval.cc materialx/nodes/invert.cc materialx/nodes/math.cc materialx/nodes/mix_rgb.cc + materialx/nodes/mix_shader.cc materialx/nodes/node_item.cc materialx/nodes/node_parser.cc materialx/nodes/normal_map.cc materialx/nodes/output_material.cc materialx/nodes/sepcomb_color.cc materialx/nodes/sepcomb_xyz.cc + materialx/nodes/subsurface_scattering.cc materialx/nodes/tex_checker.cc materialx/nodes/tex_environment.cc materialx/nodes/tex_image.cc diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 1e88124b357..a4d2f2264a7 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -17,9 +17,7 @@ namespace blender::nodes::materialx { CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader"); -MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, - Material *material, - const std::string &socket_name) +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material) { CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name); @@ -27,7 +25,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, if (material->use_nodes) { material->nodetree->ensure_topology_cache(); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); - OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute(socket_name); + OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute_full(); } else { OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default(); diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h index 4c90febce6c..b32f3ff2962 100644 --- a/source/blender/nodes/shader/materialx/material.h +++ b/source/blender/nodes/shader/materialx/material.h @@ -15,8 +15,6 @@ namespace blender::nodes::materialx { extern struct CLG_LogRef *LOG_MATERIALX_SHADER; -MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, - Material *material, - const std::string &socket_name = "Surface"); +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/add_shader.cc b/source/blender/nodes/shader/materialx/nodes/add_shader.cc new file mode 100644 index 00000000000..8ac9d7ab4c2 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/add_shader.cc @@ -0,0 +1,42 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem AddShaderNodeParser::compute() +{ + NodeItem res = empty(); + switch (shader_type_) { + case NodeItem::Type::BSDF: + case NodeItem::Type::EDF: { + NodeItem shader1 = get_input_shader(0, shader_type_); + NodeItem shader2 = get_input_shader(1, shader_type_); + + if (shader1 && !shader2) { + res = shader1; + } + else if (!shader1 && shader2) { + res = shader2; + } + else if (shader1 && shader2) { + res = shader1 + shader2; + } + break; + } + case NodeItem::Type::SurfaceShader: { + res = get_input_shader(0, shader_type_); + if (!res) { + res = get_input_shader(1, shader_type_); + } + break; + } + default: + BLI_assert_unreachable(); + } + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc new file mode 100644 index 00000000000..0b975cba89c --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.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 BSDFDiffuseNodeParser::compute() +{ + if (shader_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem res = create_node("oren_nayar_diffuse_bsdf", "BSDF"); + res.set_input("color", color); + res.set_input("roughness", roughness); + if (normal) { + res.set_input("normal", normal); + } + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc new file mode 100644 index 00000000000..092953e7eed --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFGlassNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc new file mode 100644 index 00000000000..98a372ec14c --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFGlossyNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // 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 41e93336471..2a39bd542d8 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -8,6 +8,11 @@ namespace blender::nodes::materialx { NodeItem BSDFPrincipledNodeParser::compute() { + if (shader_type_ != NodeItem::Type::SurfaceShader) { + /* TODO: implement for BSDF and EDF */ + return empty(); + } + NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3); NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float); @@ -40,9 +45,9 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float); // transparency = 1.0 - alpha - NodeItem normal = get_input_link("Normal"); - NodeItem clearcoat_normal = get_input_link("Clearcoat Normal"); - NodeItem tangent = get_input_link("Tangent"); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3); + NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); /* Creating standard_surface */ NodeItem res = create_node("standard_surface", "surfaceshader"); diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc new file mode 100644 index 00000000000..2818cb52c29 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFRefractionNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc new file mode 100644 index 00000000000..7672813a63f --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFSheenNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc new file mode 100644 index 00000000000..0c8fffa5780 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFToonNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc new file mode 100644 index 00000000000..82779b4203b --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFTranslucentNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc new file mode 100644 index 00000000000..c9310de8ac3 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BSDFTransparentNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/emission.cc b/source/blender/nodes/shader/materialx/nodes/emission.cc new file mode 100644 index 00000000000..47d090e4e7f --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/emission.cc @@ -0,0 +1,23 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem EmissionNodeParser::compute() +{ + if (shader_type_ != NodeItem::Type::EDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); + + NodeItem res = create_node("uniform_edf", "EDF"); + res.set_input("color", color * strength); + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index c974f9d46a3..b038733c6ab 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -14,7 +14,7 @@ NodeItem MathNodeParser::compute() NodeItem res = empty(); /* Single operand operations */ - NodeItem x = get_input_value(0, NodeItem::Type::Empty); + NodeItem x = get_input_value(0, NodeItem::Type::Any); switch (op) { case NODE_MATH_SINE: res = x.sin(); @@ -82,7 +82,7 @@ NodeItem MathNodeParser::compute() default: { /* 2-operand operations */ - NodeItem y = get_input_value(1, NodeItem::Type::Empty); + NodeItem y = get_input_value(1, NodeItem::Type::Any); switch (op) { case NODE_MATH_ADD: res = x + y; @@ -132,7 +132,7 @@ NodeItem MathNodeParser::compute() default: { /* 3-operand operations */ - NodeItem z = get_input_value(2, NodeItem::Type::Empty); + NodeItem z = get_input_value(2, NodeItem::Type::Any); switch (op) { case NODE_MATH_WRAP: CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); diff --git a/source/blender/nodes/shader/materialx/nodes/mix_shader.cc b/source/blender/nodes/shader/materialx/nodes/mix_shader.cc new file mode 100644 index 00000000000..fc27dc1a92a --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/mix_shader.cc @@ -0,0 +1,46 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem MixShaderNodeParser::compute() +{ + NodeItem res = empty(); + switch (shader_type_) { + case NodeItem::Type::BSDF: + case NodeItem::Type::EDF: { + NodeItem fac = get_input_value(0, NodeItem::Type::Float); + NodeItem shader1 = get_input_shader(1, shader_type_); + NodeItem shader2 = get_input_shader(2, shader_type_); + + if (shader1 && !shader2) { + res = shader1 * (value(1.0f) - fac); + } + else if (!shader1 && shader2) { + res = shader2 * fac; + } + else if (shader1 && shader2) { + res = create_node("mix", NodeItem::type(shader_type_)); + res.set_input("fg", shader1); + res.set_input("bg", shader2); + res.set_input("mix", fac); + } + break; + } + case NodeItem::Type::SurfaceShader: { + res = get_input_shader(1, shader_type_); + if (!res) { + res = get_input_shader(2, shader_type_); + } + break; + } + default: + BLI_assert_unreachable(); + } + 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 7801d540913..8c62b0bf426 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -12,6 +12,86 @@ namespace blender::nodes::materialx { NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} +NodeItem::Type NodeItem::type(const std::string &type_str) +{ + if (type_str == "string") { + return Type::String; + } + if (type_str == "filename") { + return Type::Filename; + } + if (type_str == "integer") { + return Type::Integer; + } + if (type_str == "float") { + return Type::Float; + } + if (type_str == "vector2") { + return Type::Vector2; + } + if (type_str == "vector3") { + return Type::Vector3; + } + if (type_str == "vector4") { + return Type::Vector4; + } + if (type_str == "color3") { + return Type::Color3; + } + if (type_str == "color4") { + return Type::Color4; + } + if (type_str == "BSDF") { + return Type::BSDF; + } + if (type_str == "EDF") { + return Type::EDF; + } + if (type_str == "surfaceshader") { + return Type::SurfaceShader; + } + if (type_str == "material") { + return Type::Material; + } + BLI_assert_unreachable(); + return Type::Empty; +} + +std::string NodeItem::type(Type type) +{ + switch (type) { + case Type::String: + return "string"; + case Type::Filename: + return "filename"; + case Type::Integer: + return "integer"; + case Type::Float: + return "float"; + case Type::Vector2: + return "vector2"; + case Type::Vector3: + return "vector3"; + case Type::Vector4: + return "vector4"; + case Type::Color3: + return "color3"; + case Type::Color4: + return "color4"; + case Type::BSDF: + return "BSDF"; + case Type::EDF: + return "EDF"; + case Type::SurfaceShader: + return "surfaceshader"; + case Type::Material: + return "material"; + default: + BLI_assert_unreachable(); + } + return ""; +} + NodeItem::operator bool() const { return value || node; @@ -19,6 +99,21 @@ NodeItem::operator bool() const NodeItem NodeItem::operator+(const NodeItem &other) const { + Type type = this->type(); + if (ELEM(type, Type::BSDF, Type::EDF)) { + /* Special case: add BSDF/EDF shaders */ + NodeItem res = empty(); + if (other.type() == type) { + res.node = graph_->addNode("add", MaterialX::EMPTY_STRING, this->type(type)); + res.set_input("in1", *this); + res.set_input("in2", other); + } + else { + BLI_assert_unreachable(); + } + return res; + } + return arithmetic(other, "add", [](float a, float b) { return a + b; }); } @@ -34,6 +129,22 @@ NodeItem NodeItem::operator-() const NodeItem NodeItem::operator*(const NodeItem &other) const { + Type type = this->type(); + if (ELEM(type, Type::BSDF, Type::EDF)) { + /* Special case: multiple BSDF/EDF shader by Float or Color3 */ + NodeItem res = empty(); + Type other_type = other.type(); + if (ELEM(other_type, Type::Float, Type::Color3)) { + res.node = graph_->addNode("multiply", MaterialX::EMPTY_STRING, this->type(type)); + res.set_input("in1", *this); + res.set_input("in2", other); + } + else { + BLI_assert_unreachable(); + } + return res; + } + return arithmetic(other, "multiply", [](float a, float b) { return a * b; }); } @@ -70,7 +181,7 @@ bool NodeItem::operator==(const NodeItem &other) const NodeItem item1 = *this; NodeItem item2 = other; - Type to_type = adjust_types(item1, item2); + Type to_type = cast_types(item1, item2); if (to_type == Type::Empty) { return false; } @@ -248,10 +359,14 @@ NodeItem NodeItem::extract(const int index) const NodeItem NodeItem::convert(Type to_type) const { Type from_type = type(); - if (from_type == to_type) { + if (from_type == Type::Empty || from_type == to_type || to_type == Type::Any) { return *this; } if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) { + CLOG_WARN(LOG_MATERIALX_SHADER, + "Cannot convert: %s -> %s", + type(from_type).c_str(), + type(to_type).c_str()); return empty(); } @@ -448,7 +563,7 @@ NodeItem NodeItem::if_else(CompareOp op, auto item1 = if_val; auto item2 = else_val; - Type to_type = adjust_types(item1, item2); + Type to_type = cast_types(item1, item2); if (to_type == Type::Empty) { return res; } @@ -554,66 +669,12 @@ void NodeItem::add_output(const std::string &name, Type out_type) node->addOutput(name, type(out_type)); } -NodeItem::Type NodeItem::type(const std::string &type_str) -{ - if (type_str == "string") { - return Type::String; - } - if (type_str == "integer") { - return Type::Integer; - } - if (type_str == "float") { - return Type::Float; - } - if (type_str == "vector2") { - return Type::Vector2; - } - if (type_str == "vector3") { - return Type::Vector3; - } - if (type_str == "vector4") { - return Type::Vector4; - } - if (type_str == "color3") { - return Type::Color3; - } - if (type_str == "color4") { - return Type::Color4; - } - return Type::Other; -} - -std::string NodeItem::type(Type type) -{ - switch (type) { - case Type::String: - return "string"; - case Type::Integer: - return "integer"; - case Type::Float: - return "float"; - case Type::Vector2: - return "vector2"; - case Type::Vector3: - return "vector3"; - case Type::Vector4: - return "vector4"; - case Type::Color3: - return "color3"; - case Type::Color4: - return "color4"; - default: - break; - } - return ""; -} - bool NodeItem::is_arithmetic(Type type) { - return type >= Type::Float; + return type >= Type::Float && type <= Type::Color4; } -NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2) +NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2) { Type t1 = item1.type(); Type t2 = item2.type(); @@ -621,6 +682,8 @@ NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2) return t1; } if (!is_arithmetic(t1) || !is_arithmetic(t2)) { + CLOG_WARN( + LOG_MATERIALX_SHADER, "Can't adjust types: %s <-> %s", type(t1).c_str(), type(t2).c_str()); return Type::Empty; } if (t1 < t2) { @@ -701,7 +764,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, NodeItem res = empty(); NodeItem item1 = *this; NodeItem item2 = other; - Type to_type = adjust_types(item1, item2); + Type to_type = cast_types(item1, item2); if (to_type == Type::Empty) { return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 19e29ef1854..6a223a4d850 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -11,16 +11,28 @@ namespace blender::nodes::materialx { class NodeItem { public: enum class Type { - Empty = 0, - Other, /* For MaterialX types like: surfaceshader, bsdf, edf, ...*/ + Any = 0, + Empty, + + /* Value types */ String, + Filename, Integer, + /* Block of arithmetic types. Ordered by type cast */ Float, Vector2, Vector3, - Vector4, Color3, - Color4 + Vector4, + Color4, + /* End of arithmetic types */ + + /* Shader types + * NOTE: There are only supported types */ + BSDF, + EDF, + SurfaceShader, + Material, }; enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq }; @@ -35,6 +47,9 @@ class NodeItem { NodeItem(MaterialX::GraphElement *graph); ~NodeItem() = default; + static Type type(const std::string &type_str); + static std::string type(Type type); + /* Operators */ operator bool() const; NodeItem operator+(const NodeItem &other) const; @@ -92,10 +107,8 @@ class NodeItem { void add_output(const std::string &in_name, Type out_type); private: - static Type type(const std::string &type_str); - static std::string type(Type type); static bool is_arithmetic(Type type); - static Type adjust_types(NodeItem &item1, NodeItem &item2); + static Type cast_types(NodeItem &item1, NodeItem &item2); bool is_arithmetic() const; NodeItem arithmetic(const std::string &category, std::function func) const; diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index ec3462efb80..b1987955cd1 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -22,11 +22,21 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph, { } -std::string NodeParser::node_name(const bNode *node, const bNodeSocket *socket_out) +NodeItem NodeParser::compute_full() { - return MaterialX::createValidName(node->output_sockets().size() <= 1 ? - std::string(node->name) : - std::string(node->name) + "_" + socket_out->name); + CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type); + NodeItem res = compute(); + if (res.node) { + res.node->setName(node_name()); + } + return res; +} + +std::string NodeParser::node_name() +{ + return MaterialX::createValidName(node_->output_sockets().size() <= 1 ? + std::string(node_->name) : + std::string(node_->name) + "_" + socket_out_->name); } NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type) @@ -36,34 +46,34 @@ NodeItem NodeParser::create_node(const std::string &mx_category, const std::stri return res; } -NodeItem NodeParser::get_input_default(const std::string &name) +NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) { - return get_input_default(node_->input_by_identifier(name)); + return get_input_default(node_->input_by_identifier(name), to_type); } -NodeItem NodeParser::get_input_default(int index) +NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type) { - return get_input_default(node_->input_socket(index)); + return get_input_default(node_->input_socket(index), to_type); } -NodeItem NodeParser::get_input_link(const std::string &name) +NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type) { - return get_input_link(node_->input_by_identifier(name)); + return get_input_link(node_->input_by_identifier(name), to_type); } -NodeItem NodeParser::get_input_link(int index) +NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type) { - return get_input_link(node_->input_socket(index)); + return get_input_link(node_->input_socket(index), to_type); } -NodeItem NodeParser::get_input_value(const std::string &name, const NodeItem::Type type) +NodeItem NodeParser::get_input_value(const std::string &name, NodeItem::Type to_type) { - return get_input_value(node_->input_by_identifier(name), type); + return get_input_value(node_->input_by_identifier(name), to_type); } -NodeItem NodeParser::get_input_value(int index, const NodeItem::Type type) +NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type) { - return get_input_value(node_->input_socket(index), type); + return get_input_value(node_->input_socket(index), to_type); } NodeItem NodeParser::empty() const @@ -71,7 +81,7 @@ NodeItem NodeParser::empty() const return NodeItem(graph_); } -NodeItem NodeParser::get_input_default(const bNodeSocket &socket) +NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type) { NodeItem res = empty(); switch (socket.type) { @@ -96,10 +106,10 @@ NodeItem NodeParser::get_input_default(const bNodeSocket &socket) CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type); } } - return res; + return res.convert(to_type); } -NodeItem NodeParser::get_input_link(const bNodeSocket &socket) +NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to_type) { NodeItem res = empty(); @@ -119,21 +129,16 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) from_node = link->fromnode; } - /* Checking if node was already computed */ - res.node = graph_->getNode(node_name(from_node, link->fromsock)); - if (res.node) { - return res; - } + /* Creating required NodeParser object */ + std::unique_ptr parser; - /* Computing from_node with required NodeParser object */ #define CASE_NODE_TYPE(type, T) \ case type: \ - res = T(graph_, depsgraph_, material_, from_node, link->fromsock).compute_full(); \ + parser = std::make_unique(graph_, depsgraph_, material_, from_node, link->fromsock); \ 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) @@ -155,27 +160,137 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket) from_node->name, from_node->typeinfo->type); } + if (!parser) { + return res; + } + /* Checking if node was already computed */ + res.node = graph_->getNode(parser->node_name()); + if (res.node) { + return res; + } + + /* Computing */ + res = parser->compute_full(); + return res.convert(to_type); +} + +NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type to_type) +{ + NodeItem res = get_input_link(socket, to_type); + if (!res) { + res = get_input_default(socket, to_type); + } return res; } -NodeItem NodeParser::get_input_value(const bNodeSocket &socket, const NodeItem::Type type) +ShaderNodeParser::ShaderNodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node, + const bNodeSocket *socket_out, + NodeItem::Type shader_type) + : NodeParser(graph, depsgraph, material, node, socket_out), shader_type_(shader_type) { - NodeItem res = get_input_link(socket); - if (!res) { - res = get_input_default(socket); - } - return type == NodeItem::Type::Empty ? res : res.convert(type); } -NodeItem NodeParser::compute_full() +NodeItem ShaderNodeParser::compute_full() { - CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type); + CLOG_INFO(LOG_MATERIALX_SHADER, + 1, + "%s [%d] - %s", + node_->name, + node_->typeinfo->type, + NodeItem::type(shader_type_).c_str()); NodeItem res = compute(); if (res.node) { - res.node->setName(node_name(node_, socket_out_)); + res.node->setName(node_name()); } return res; } +std::string ShaderNodeParser::node_name() +{ + std::string name = NodeParser::node_name(); + if (shader_type_ != NodeItem::Type::SurfaceShader) { + name += "_" + NodeItem::type(shader_type_); + } + return name; +} + +NodeItem ShaderNodeParser::get_input_shader(const std::string &name, NodeItem::Type shader_type) +{ + return get_input_shader(node_->input_by_identifier(name), shader_type); +} + +NodeItem ShaderNodeParser::get_input_shader(int index, NodeItem::Type shader_type) +{ + return get_input_shader(node_->input_socket(index), shader_type); +} + +NodeItem ShaderNodeParser::get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type) +{ + NodeItem res = empty(); + + const bNodeLink *link = socket.link; + if (!(link && link->is_used())) { + return res; + } + + const bNode *from_node = link->fromnode; + + /* Passing NODE_REROUTE nodes */ + while (from_node->type == NODE_REROUTE) { + link = from_node->input_socket(0).link; + if (!(link && link->is_used())) { + return res; + } + from_node = link->fromnode; + } + + /* Creating required ShaderNodeParser object */ + std::unique_ptr parser; + +#define CASE_SHADER_NODE_TYPE(type, T) \ + case type: \ + parser = std::make_unique( \ + graph_, depsgraph_, material_, from_node, link->fromsock, shader_type); \ + break; + + switch (from_node->typeinfo->type) { + CASE_SHADER_NODE_TYPE(SH_NODE_ADD_SHADER, AddShaderNodeParser) + CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_DIFFUSE, BSDFDiffuseNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLASS, BSDFGlassNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLOSSY, BSDFGlossyNodeParser) + CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_REFRACTION, BSDFRefractionNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_SHEEN, BSDFSheenNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TOON, BSDFToonNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSLUCENT, BSDFTranslucentNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSPARENT, BSDFTransparentNodeParser) + CASE_SHADER_NODE_TYPE(SH_NODE_EMISSION, EmissionNodeParser) + CASE_SHADER_NODE_TYPE(SH_NODE_MIX_SHADER, MixShaderNodeParser) + // CASE_SHADER_NODE_TYPE(SH_NODE_SUBSURFACE_SCATTERING, SubsurfaceScatteringNodeParser) + + default: + CLOG_WARN(LOG_MATERIALX_SHADER, + "Unsupported node: %s [%d]", + from_node->name, + from_node->typeinfo->type); + } + if (!parser) { + return res; + } + + /* Checking if node was already computed */ + res.node = graph_->getNode(parser->node_name()); + if (res.node) { + return res; + } + + /* Computing */ + res = parser->compute_full(); + return res; +} + } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 15243b74f99..eb4502d6cd0 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -31,24 +31,44 @@ class NodeParser { virtual NodeItem compute() = 0; protected: - static std::string node_name(const bNode *node, const bNodeSocket *socket_out); + virtual NodeItem compute_full(); + virtual std::string node_name(); NodeItem create_node(const std::string &mx_category, const std::string &mx_type); - NodeItem get_input_default(const std::string &name); - NodeItem get_input_default(int index); - NodeItem get_input_link(const std::string &name); - NodeItem get_input_link(int index); - NodeItem get_input_value(const std::string &name, - const NodeItem::Type type); - NodeItem get_input_value(int index, const NodeItem::Type type); + NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); + NodeItem get_input_default(int index, NodeItem::Type to_type); + NodeItem get_input_link(const std::string &name, NodeItem::Type to_type); + NodeItem get_input_link(int index, NodeItem::Type to_type); + NodeItem get_input_value(const std::string &name, NodeItem::Type to_type); + NodeItem get_input_value(int index, NodeItem::Type to_type); NodeItem empty() const; template NodeItem value(const T &data) const; private: - NodeItem get_input_default(const bNodeSocket &socket); - NodeItem get_input_link(const bNodeSocket &socket); - NodeItem get_input_value(const bNodeSocket &socket, - const NodeItem::Type type); - NodeItem compute_full(); + NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); + NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type); + NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type); +}; + +class ShaderNodeParser : public NodeParser { + protected: + NodeItem::Type shader_type_; + + public: + ShaderNodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node, + const bNodeSocket *socket_out, + NodeItem::Type shader_type); + + protected: + NodeItem compute_full() override; + std::string node_name() override; + NodeItem get_input_shader(const std::string &name, NodeItem::Type shader_type); + NodeItem get_input_shader(int index, NodeItem::Type shader_type); + + private: + NodeItem get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type); }; template NodeItem NodeParser::value(const T &data) const @@ -56,28 +76,48 @@ template NodeItem NodeParser::value(const T &data) const return empty().val(data); } -#define DECLARE_PARSER(T) \ +#define DECLARE_NODE_PARSER(T) \ class T : public NodeParser { \ public: \ using NodeParser::NodeParser; \ 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) +#define DECLARE_SHADER_NODE_PARSER(T) \ + class T : public ShaderNodeParser { \ + public: \ + using ShaderNodeParser::ShaderNodeParser; \ + NodeItem compute() override; \ + }; + +DECLARE_NODE_PARSER(BrightContrastNodeParser) +DECLARE_NODE_PARSER(CombineColorNodeParser) +DECLARE_NODE_PARSER(CombineXYZNodeParser) +DECLARE_NODE_PARSER(HueSatValNodeParser) +DECLARE_NODE_PARSER(InvertNodeParser) +DECLARE_NODE_PARSER(MathNodeParser) +DECLARE_NODE_PARSER(MixRGBNodeParser) +DECLARE_NODE_PARSER(NormalMapNodeParser) +DECLARE_NODE_PARSER(SeparateColorNodeParser) +DECLARE_NODE_PARSER(SeparateXYZNodeParser) +DECLARE_NODE_PARSER(TexCheckerNodeParser) +DECLARE_NODE_PARSER(TexEnvironmentNodeParser) +DECLARE_NODE_PARSER(TexImageNodeParser) +DECLARE_NODE_PARSER(TexNoiseNodeParser) +DECLARE_NODE_PARSER(VectorMathNodeParser) + +DECLARE_SHADER_NODE_PARSER(AddShaderNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFDiffuseNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFGlassNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFGlossyNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFPrincipledNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFRefractionNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFSheenNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFToonNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFTranslucentNodeParser) +DECLARE_SHADER_NODE_PARSER(BSDFTransparentNodeParser) +DECLARE_SHADER_NODE_PARSER(EmissionNodeParser) +DECLARE_SHADER_NODE_PARSER(MixShaderNodeParser) +DECLARE_SHADER_NODE_PARSER(SubsurfaceScatteringNodeParser) } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index 92fd81dbbe2..99d071973c8 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -9,27 +9,34 @@ OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *grap const Depsgraph *depsgraph, const Material *material, const bNode *node) - : NodeParser(graph, depsgraph, material, node, nullptr) + : ShaderNodeParser(graph, depsgraph, material, node, nullptr, NodeItem::Type::Material) { } NodeItem OutputMaterialNodeParser::compute() -{ - return empty(); -} - -NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name) { NodeItem surface = empty(); if (node_) { - surface = get_input_link(socket_name); + NodeItem bsdf = get_input_shader("Surface", NodeItem::Type::BSDF); + NodeItem edf = get_input_shader("Surface", NodeItem::Type::EDF); + if (bsdf || edf) { + surface = create_node("surface", "surfaceshader"); + if (bsdf) { + surface.set_input("bsdf", bsdf); + } + if (edf) { + surface.set_input("edf", edf); + } + } + else { + surface = get_input_shader("Surface", NodeItem::Type::SurfaceShader); + } } else { surface = create_node("standard_surface", "surfaceshader"); surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f))); } NodeItem res = create_node("surfacematerial", "material"); - res.node->setName(node_name(node_, nullptr)); res.set_input("surfaceshader", surface); return res; } @@ -55,4 +62,9 @@ NodeItem OutputMaterialNodeParser::compute_default() return res; } +std::string OutputMaterialNodeParser::node_name() +{ + return NodeParser::node_name(); +} + } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.h b/source/blender/nodes/shader/materialx/nodes/output_material.h index 986c926f33d..9f75d8761f8 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.h +++ b/source/blender/nodes/shader/materialx/nodes/output_material.h @@ -8,15 +8,19 @@ namespace blender::nodes::materialx { -class OutputMaterialNodeParser : public NodeParser { +class OutputMaterialNodeParser : public ShaderNodeParser { public: OutputMaterialNodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, const bNode *node); NodeItem compute() override; - NodeItem compute(const std::string &socket_name); + + using ShaderNodeParser::compute_full; NodeItem compute_default(); + + protected: + std::string node_name() override; }; } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc b/source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc new file mode 100644 index 00000000000..7efddb150a6 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem SubsurfaceScatteringNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index 7cf1d8ee52a..f039a6336e4 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -8,7 +8,7 @@ namespace blender::nodes::materialx { NodeItem TexCheckerNodeParser::compute() { - NodeItem vector = get_input_link("Vector"); + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); NodeItem color1 = get_input_value("Color1", NodeItem::Type::Color3); NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3); NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); @@ -16,28 +16,13 @@ NodeItem TexCheckerNodeParser::compute() if (!vector) { vector = create_node("texcoord", "vector2"); } - vector = vector * scale; - - NodeItem separate = create_node("separate2", "multioutput"); - separate.set_input("in", vector); - separate.add_output("outx", NodeItem::Type::Float); - separate.add_output("outy", NodeItem::Type::Float); - - NodeItem modulo_x = create_node("modulo", "float"); - modulo_x.set_input("in1", separate, "outx"); - modulo_x.set_input("in2", value(2.0f)); - - NodeItem modulo_y = create_node("modulo", "float"); - modulo_y.set_input("in1", separate, "outy"); - modulo_y.set_input("in2", value(2.0f)); - - NodeItem ifequal = (modulo_x.floor() + modulo_y.floor()) - .if_else(NodeItem::CompareOp::Eq, value(1.0f), value(0.0f), value(1.0f)); - + vector = (vector * scale) % value(2.0f); + NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor()) + .if_else(NodeItem::CompareOp::Eq, value(1.0f), value(1.0f), value(0.0f)); NodeItem res = create_node("mix", "color3"); - res.set_input("bg", color1); - res.set_input("fg", color2); - res.set_input("mix", ifequal); + res.set_input("fg", color1); + res.set_input("bg", color2); + res.set_input("mix", mix); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/vector_math.cc b/source/blender/nodes/shader/materialx/nodes/vector_math.cc index df476460969..a3267565772 100644 --- a/source/blender/nodes/shader/materialx/nodes/vector_math.cc +++ b/source/blender/nodes/shader/materialx/nodes/vector_math.cc @@ -14,7 +14,7 @@ NodeItem VectorMathNodeParser::compute() NodeItem res = empty(); /* Single operand operations */ - NodeItem x = get_input_value(0, NodeItem::Type::Empty); + NodeItem x = get_input_value(0, NodeItem::Type::Any); switch (op) { case NODE_VECTOR_MATH_SINE: res = x.sin(); @@ -46,7 +46,7 @@ NodeItem VectorMathNodeParser::compute() default: { /* 2-operand operations */ - NodeItem y = get_input_value(1, NodeItem::Type::Empty); + NodeItem y = get_input_value(1, NodeItem::Type::Any); switch (op) { case NODE_VECTOR_MATH_ADD: res = x + y; @@ -93,7 +93,7 @@ NodeItem VectorMathNodeParser::compute() default: { /* 3-operand operations */ - NodeItem z = get_input_value(2, NodeItem::Type::Empty); + NodeItem z = get_input_value(2, NodeItem::Type::Any); switch (op) { case NODE_VECTOR_MATH_MULTIPLY_ADD: res = x * y + z; -- 2.30.2 From a610ec2ba3a7bc0009a25b526b0241e6d5762bd9 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 7 Sep 2023 15:10:04 +0200 Subject: [PATCH 14/40] Parsing Improvements ### Purpose Perform parsing Improvements ### Technical steps * Added `NodeItem::create_node()` * Added `NodeItem::set_input_output()` * Removed `NodeItem::set_input()` with `out_name` parameter * `NodeParser::create_node()`: changed type to `NodeItem::Type` * Logging improvements * `NodeParser::value()` -> `NodeParser::val()` * Renamings and code improvements Pull Request: https://projects.blender.org/DagerD/blender/pulls/14 --- .../nodes/shader/materialx/material.cc | 2 +- .../shader/materialx/nodes/brightness.cc | 2 +- .../shader/materialx/nodes/bsdf_diffuse.cc | 2 +- .../shader/materialx/nodes/bsdf_principled.cc | 4 +- .../nodes/shader/materialx/nodes/emission.cc | 2 +- .../nodes/shader/materialx/nodes/huesatval.cc | 10 +-- .../nodes/shader/materialx/nodes/math.cc | 16 ++-- .../shader/materialx/nodes/mix_shader.cc | 8 +- .../nodes/shader/materialx/nodes/node_item.cc | 73 +++++++++++-------- .../nodes/shader/materialx/nodes/node_item.h | 15 ++-- .../shader/materialx/nodes/node_parser.cc | 6 +- .../shader/materialx/nodes/node_parser.h | 6 +- .../shader/materialx/nodes/normal_map.cc | 8 +- .../shader/materialx/nodes/output_material.cc | 24 +++--- .../shader/materialx/nodes/sepcomb_color.cc | 10 +-- .../shader/materialx/nodes/sepcomb_xyz.cc | 2 +- .../shader/materialx/nodes/tex_checker.cc | 8 +- .../shader/materialx/nodes/tex_environment.cc | 6 +- .../nodes/shader/materialx/nodes/tex_image.cc | 6 +- .../nodes/shader/materialx/nodes/tex_noise.cc | 6 +- .../shader/materialx/nodes/vector_math.cc | 2 +- 21 files changed, 115 insertions(+), 103 deletions(-) diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index a4d2f2264a7..1902d1dc2f5 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -32,7 +32,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater } CLOG_INFO(LOG_MATERIALX_SHADER, - 2, + 1, "Material: %s\n%s", material->id.name, MaterialX::writeToXmlString(doc).c_str()); diff --git a/source/blender/nodes/shader/materialx/nodes/brightness.cc b/source/blender/nodes/shader/materialx/nodes/brightness.cc index 7c3261c9f2b..01beec5ca38 100644 --- a/source/blender/nodes/shader/materialx/nodes/brightness.cc +++ b/source/blender/nodes/shader/materialx/nodes/brightness.cc @@ -13,7 +13,7 @@ NodeItem BrightContrastNodeParser::compute() NodeItem contrast = get_input_value("Contrast", NodeItem::Type::Float); /* 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)); + return (bright + color * (contrast + val(1.0f)) - contrast * val(0.5f)).max(val(0.0f)); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc index 0b975cba89c..7ef11fb9bbc 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc @@ -16,7 +16,7 @@ NodeItem BSDFDiffuseNodeParser::compute() NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem res = create_node("oren_nayar_diffuse_bsdf", "BSDF"); + NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF); res.set_input("color", color); res.set_input("roughness", roughness); if (normal) { diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc index 2a39bd542d8..7ce0b153b31 100644 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ b/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc @@ -50,8 +50,8 @@ NodeItem BSDFPrincipledNodeParser::compute() NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); /* Creating standard_surface */ - NodeItem res = create_node("standard_surface", "surfaceshader"); - res.set_input("base", 1.0, "float"); + NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader); + res.set_input("base", val(1.0f)); res.set_input("base_color", base_color); res.set_input("diffuse_roughness", roughness); if (normal) { diff --git a/source/blender/nodes/shader/materialx/nodes/emission.cc b/source/blender/nodes/shader/materialx/nodes/emission.cc index 47d090e4e7f..f737c328bc8 100644 --- a/source/blender/nodes/shader/materialx/nodes/emission.cc +++ b/source/blender/nodes/shader/materialx/nodes/emission.cc @@ -15,7 +15,7 @@ NodeItem EmissionNodeParser::compute() NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); - NodeItem res = create_node("uniform_edf", "EDF"); + NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF); res.set_input("color", color * strength); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/huesatval.cc b/source/blender/nodes/shader/materialx/nodes/huesatval.cc index 05723f49a3f..3f66e2f5ca0 100644 --- a/source/blender/nodes/shader/materialx/nodes/huesatval.cc +++ b/source/blender/nodes/shader/materialx/nodes/huesatval.cc @@ -12,19 +12,19 @@ NodeItem HueSatValNodeParser::compute() * source\blender\nodes\texture\nodes\node_texture_hueSatVal.cc */ NodeItem hue = get_input_value("Hue", NodeItem::Type::Float); NodeItem saturation = get_input_value("Saturation", NodeItem::Type::Float); - NodeItem val = get_input_value("Value", NodeItem::Type::Float); + NodeItem value = get_input_value("Value", NodeItem::Type::Float); NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); NodeItem color = get_input_value("Color", NodeItem::Type::Color3); /* Modifier to follow Cycles result */ - hue = hue - value(0.5f); + hue = hue - val(0.5f); - NodeItem combine = create_node("combine3", "vector3"); + NodeItem combine = create_node("combine3", NodeItem::Type::Vector3); combine.set_input("in1", hue); combine.set_input("in2", saturation); - combine.set_input("in3", val); + combine.set_input("in3", value); - NodeItem res = create_node("hsvadjust", "color3"); + NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3); res.set_input("in", color); res.set_input("amount", combine); return res; diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index b038733c6ab..d7dd43cb004 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -35,7 +35,7 @@ NodeItem MathNodeParser::compute() res = x.atan(); break; case NODE_MATH_ROUND: - res = (x + value(0.5f)).floor(); + res = (x + val(0.5f)).floor(); break; case NODE_MATH_ABSOLUTE: res = x.abs(); @@ -47,13 +47,13 @@ NodeItem MathNodeParser::compute() res = x.ceil(); break; case NODE_MATH_FRACTION: - res = x % value(1.0f); + res = x % val(1.0f); break; case NODE_MATH_SQRT: res = x.sqrt(); break; case NODE_MATH_INV_SQRT: - res = value(1.0f) / x.sqrt(); + res = val(1.0f) / x.sqrt(); break; case NODE_MATH_SIGN: res = x.sign(); @@ -62,10 +62,10 @@ NodeItem MathNodeParser::compute() res = x.exp(); break; case NODE_MATH_RADIANS: - res = x * value(float(M_PI) / 180.0f); + res = x * val(float(M_PI) / 180.0f); break; case NODE_MATH_DEGREES: - res = x * value(180.0f * float(M_1_PI)); + res = x * val(180.0f * float(M_1_PI)); break; case NODE_MATH_SINH: res = x.sinh(); @@ -109,10 +109,10 @@ NodeItem MathNodeParser::compute() res = x.max(y); break; case NODE_MATH_LESS_THAN: - res = x.if_else(NodeItem::CompareOp::Less, y, value(1.0f), value(0.0f)); + res = x.if_else(NodeItem::CompareOp::Less, y, val(1.0f), val(0.0f)); break; case NODE_MATH_GREATER_THAN: - res = x.if_else(NodeItem::CompareOp::Greater, y, value(1.0f), value(0.0f)); + res = x.if_else(NodeItem::CompareOp::Greater, y, val(1.0f), val(0.0f)); break; case NODE_MATH_MODULO: res = x % y; @@ -138,7 +138,7 @@ NodeItem MathNodeParser::compute() CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); break; case NODE_MATH_COMPARE: - res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), value(1.0f), value(0.0f)); + res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), val(1.0f), val(0.0f)); break; case NODE_MATH_MULTIPLY_ADD: res = x * y + z; diff --git a/source/blender/nodes/shader/materialx/nodes/mix_shader.cc b/source/blender/nodes/shader/materialx/nodes/mix_shader.cc index fc27dc1a92a..40a1575d24c 100644 --- a/source/blender/nodes/shader/materialx/nodes/mix_shader.cc +++ b/source/blender/nodes/shader/materialx/nodes/mix_shader.cc @@ -17,13 +17,13 @@ NodeItem MixShaderNodeParser::compute() NodeItem shader2 = get_input_shader(2, shader_type_); if (shader1 && !shader2) { - res = shader1 * (value(1.0f) - fac); + res = shader1 * (val(1.0f) - fac); } else if (!shader1 && shader2) { res = shader2 * fac; } else if (shader1 && shader2) { - res = create_node("mix", NodeItem::type(shader_type_)); + res = create_node("mix", shader_type_); res.set_input("fg", shader1); res.set_input("bg", shader2); res.set_input("mix", fac); @@ -31,9 +31,9 @@ NodeItem MixShaderNodeParser::compute() break; } case NodeItem::Type::SurfaceShader: { - res = get_input_shader(1, shader_type_); + res = get_input_shader(1, NodeItem::Type::SurfaceShader); if (!res) { - res = get_input_shader(2, shader_type_); + res = get_input_shader(2, NodeItem::Type::SurfaceShader); } break; } diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index 8c62b0bf426..158a7178473 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -104,7 +104,7 @@ NodeItem NodeItem::operator+(const NodeItem &other) const /* Special case: add BSDF/EDF shaders */ NodeItem res = empty(); if (other.type() == type) { - res.node = graph_->addNode("add", MaterialX::EMPTY_STRING, this->type(type)); + res = create_node("add", type); res.set_input("in1", *this); res.set_input("in2", other); } @@ -135,7 +135,7 @@ NodeItem NodeItem::operator*(const NodeItem &other) const NodeItem res = empty(); Type other_type = other.type(); if (ELEM(other_type, Type::Float, Type::Color3)) { - res.node = graph_->addNode("multiply", MaterialX::EMPTY_STRING, this->type(type)); + res = create_node("multiply", type); res.set_input("in1", *this); res.set_input("in2", other); } @@ -222,9 +222,8 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const { NodeItem d = arithmetic(other, "dotproduct", [](float a, float b) { return a * b; }); if (d.value) { - Type mx_type = d.type(); float f = 0.0f; - switch (mx_type) { + switch (d.type()) { case Type::Float: { f = value->asA(); break; @@ -350,7 +349,7 @@ NodeItem NodeItem::exp() const NodeItem NodeItem::extract(const int index) const { NodeItem res = empty(); - res.node = graph_->addNode("extract", MaterialX::EMPTY_STRING, "float"); + res = create_node("extract", Type::Float); res.set_input("in", *this); res.set_input("index", val(index)); return res; @@ -534,7 +533,7 @@ NodeItem NodeItem::convert(Type to_type) const } } else { - res.node = graph_->addNode("convert", MaterialX::EMPTY_STRING, type(to_type)); + res = create_node("convert", to_type); res.set_input("in", *this); } return res; @@ -569,18 +568,18 @@ NodeItem NodeItem::if_else(CompareOp op, } std::function func = nullptr; - std::string mx_category; + std::string category; switch (op) { case CompareOp::Greater: - mx_category = "ifgreater"; + category = "ifgreater"; func = [](float a, float b) { return a > b; }; break; case CompareOp::GreaterEq: - mx_category = "ifgreatereq"; + category = "ifgreatereq"; func = [](float a, float b) { return a >= b; }; break; case CompareOp::Eq: - mx_category = "ifequal"; + category = "ifequal"; func = [](float a, float b) { return a == b; }; break; default: @@ -591,7 +590,7 @@ NodeItem NodeItem::if_else(CompareOp op, res = func(value->asA(), other.value->asA()) ? item1 : item2; } else { - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(to_type)); + res = create_node(category, to_type); res.set_input("value1", *this); res.set_input("value2", other); res.set_input("in1", item1); @@ -617,53 +616,67 @@ NodeItem::Type NodeItem::type() const return Type::Empty; } -void NodeItem::set_input(const std::string &name, - const NodeItem &item, - const std::string &output_name) +NodeItem NodeItem::create_node(const std::string &category, NodeItem::Type type) const +{ + std::string type_str = this->type(type); + CLOG_INFO(LOG_MATERIALX_SHADER, 2, "<%s type=%s>", category.c_str(), type_str.c_str()); + NodeItem res = empty(); + res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type_str); + return res; +} + +void NodeItem::set_input(const std::string &in_name, const NodeItem &item) { if (item.value) { Type item_type = item.type(); - std::string mx_type = type(item_type); switch (item_type) { case Type::String: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Integer: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Float: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Vector2: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Vector3: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Vector4: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Color3: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; case Type::Color4: - set_input(name, item.value->asA(), mx_type); + set_input(in_name, item.value->asA(), item_type); break; default: BLI_assert_unreachable(); } } else if (item.node) { - node->setConnectedNode(name, item.node); - if (output_name != "") { - node->setConnectedOutput(name, item.node->getOutput(output_name)); - } + node->setConnectedNode(in_name, item.node); } else { - CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str()); + CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", in_name.c_str()); } } +void NodeItem::set_input_output(const std::string &in_name, + const NodeItem &item, + const std::string &out_name) +{ + if (!item.node) { + BLI_assert_unreachable(); + } + node->setConnectedNode(in_name, item.node); + node->setConnectedOutput(in_name, item.node->getOutput(out_name)); +} + void NodeItem::add_output(const std::string &name, Type out_type) { node->addOutput(name, type(out_type)); @@ -751,7 +764,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::functionaddNode(category, MaterialX::EMPTY_STRING, this->type(type)); + res = create_node(category, type); res.set_input("in", *this); } return res; @@ -817,7 +830,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other, } } else { - res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type(to_type)); + res = create_node(category, to_type); res.set_input("in1", item1); res.set_input("in2", item2); } diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 6a223a4d850..288dd70f3d5 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -97,13 +97,14 @@ class NodeItem { NodeItem empty() const; template NodeItem val(const T &data) const; Type type() const; + NodeItem create_node(const std::string &category, NodeItem::Type type) const; /* Functions to set input and output */ - template - void set_input(const std::string &in_name, const T &value, const std::string &in_type); - void set_input(const std::string &in_name, - const NodeItem &item, - const std::string &out_name = ""); + template void set_input(const std::string &in_name, const T &value, Type in_type); + void set_input(const std::string &in_name, const NodeItem &item); + void set_input_output(const std::string &in_name, + const NodeItem &item, + const std::string &out_name); void add_output(const std::string &in_name, Type out_type); private: @@ -125,9 +126,9 @@ template NodeItem NodeItem::val(const T &data) const } template -void NodeItem::set_input(const std::string &in_name, const T &value, const std::string &in_type) +void NodeItem::set_input(const std::string &in_name, const T &value, Type in_type) { - node->setInputValue(in_name, value, in_type); + node->setInputValue(in_name, value, type(in_type)); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index b1987955cd1..4a287932875 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -39,11 +39,9 @@ std::string NodeParser::node_name() std::string(node_->name) + "_" + socket_out_->name); } -NodeItem NodeParser::create_node(const std::string &mx_category, const std::string &mx_type) +NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type) { - NodeItem res = empty(); - res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, mx_type); - return res; + return empty().create_node(category, type); } NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index eb4502d6cd0..aed8803474c 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -33,7 +33,7 @@ class NodeParser { protected: virtual NodeItem compute_full(); virtual std::string node_name(); - NodeItem create_node(const std::string &mx_category, const std::string &mx_type); + NodeItem create_node(const std::string &category, NodeItem::Type type); NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); NodeItem get_input_default(int index, NodeItem::Type to_type); NodeItem get_input_link(const std::string &name, NodeItem::Type to_type); @@ -41,7 +41,7 @@ class NodeParser { NodeItem get_input_value(const std::string &name, NodeItem::Type to_type); NodeItem get_input_value(int index, NodeItem::Type to_type); NodeItem empty() const; - template NodeItem value(const T &data) const; + template NodeItem val(const T &data) const; private: NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); @@ -71,7 +71,7 @@ class ShaderNodeParser : public NodeParser { NodeItem get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type); }; -template NodeItem NodeParser::value(const T &data) const +template NodeItem NodeParser::val(const T &data) const { return empty().val(data); } diff --git a/source/blender/nodes/shader/materialx/nodes/normal_map.cc b/source/blender/nodes/shader/materialx/nodes/normal_map.cc index 8145a3444ac..1a51911a22f 100644 --- a/source/blender/nodes/shader/materialx/nodes/normal_map.cc +++ b/source/blender/nodes/shader/materialx/nodes/normal_map.cc @@ -14,19 +14,19 @@ NodeItem NormalMapNodeParser::compute() NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); - NodeItem res = create_node("normalmap", "vector3"); + NodeItem res = create_node("normalmap", NodeItem::Type::Vector3); res.set_input("in", color); res.set_input("scale", strength); switch (normal_map_node->space) { case SHD_SPACE_TANGENT: - res.set_input("space", value(std::string("tangent"))); + res.set_input("space", val(std::string("tangent"))); break; case SHD_SPACE_OBJECT: - res.set_input("space", value(std::string("tangent"))); + res.set_input("space", val(std::string("tangent"))); break; default: - res.set_input("space", value(default_space)); + res.set_input("space", val(default_space)); CLOG_WARN(LOG_MATERIALX_SHADER, "Ignoring unsupported Space: %d %s (%d), %s will be used", normal_map_node->space, diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc index 99d071973c8..4de4991d1dd 100644 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ b/source/blender/nodes/shader/materialx/nodes/output_material.cc @@ -20,7 +20,7 @@ NodeItem OutputMaterialNodeParser::compute() NodeItem bsdf = get_input_shader("Surface", NodeItem::Type::BSDF); NodeItem edf = get_input_shader("Surface", NodeItem::Type::EDF); if (bsdf || edf) { - surface = create_node("surface", "surfaceshader"); + surface = create_node("surface", NodeItem::Type::SurfaceShader); if (bsdf) { surface.set_input("bsdf", bsdf); } @@ -33,30 +33,30 @@ NodeItem OutputMaterialNodeParser::compute() } } else { - surface = create_node("standard_surface", "surfaceshader"); - surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f))); + surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); + surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f))); } - NodeItem res = create_node("surfacematerial", "material"); + NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); res.set_input("surfaceshader", surface); return res; } NodeItem OutputMaterialNodeParser::compute_default() { - NodeItem surface = create_node("standard_surface", "surfaceshader"); + NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); surface.set_input("base_color", - value(MaterialX::Color3(material_->r, material_->g, material_->b))); - surface.set_input("diffuse_roughness", value(material_->roughness)); + val(MaterialX::Color3(material_->r, material_->g, material_->b))); + surface.set_input("diffuse_roughness", val(material_->roughness)); if (material_->metallic > 0.0f) { - surface.set_input("metalness", value(material_->metallic)); + surface.set_input("metalness", val(material_->metallic)); } if (material_->spec) { - surface.set_input("specular", value(material_->spec)); - surface.set_input("specular_color", value(material_->spec)); - surface.set_input("specular_roughness", value(material_->roughness)); + surface.set_input("specular", val(material_->spec)); + surface.set_input("specular_color", val(material_->spec)); + surface.set_input("specular_roughness", val(material_->roughness)); } - NodeItem res = create_node("surfacematerial", "material"); + NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); res.node->setName("Material_Default"); res.set_input("surfaceshader", surface); return res; diff --git a/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc b/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc index 7867808285d..e3398d8a4a4 100644 --- a/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc +++ b/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc @@ -18,12 +18,12 @@ NodeItem SeparateColorNodeParser::compute() case NODE_COMBSEP_COLOR_RGB: break; case NODE_COMBSEP_COLOR_HSV: - convert = create_node("rgbtohsv", "color3"); + convert = create_node("rgbtohsv", NodeItem::Type::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 = create_node("rgbtohsv", NodeItem::Type::Color3); convert.set_input("in", color); break; default: @@ -44,7 +44,7 @@ NodeItem CombineColorNodeParser::compute() NodeItem blue = get_input_value("Blue", NodeItem::Type::Float); NodeItem convert = empty(); - NodeItem combine = create_node("combine3", "color3"); + NodeItem combine = create_node("combine3", NodeItem::Type::Color3); combine.set_input("in1", red); combine.set_input("in2", green); combine.set_input("in3", blue); @@ -53,12 +53,12 @@ NodeItem CombineColorNodeParser::compute() case NODE_COMBSEP_COLOR_RGB: break; case NODE_COMBSEP_COLOR_HSV: - convert = create_node("hsvtorgb", "color3"); + convert = create_node("hsvtorgb", NodeItem::Type::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 = create_node("hsvtorgb", NodeItem::Type::Color3); convert.set_input("in", combine); break; default: diff --git a/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc b/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc index 1143a97511d..e228edf708a 100644 --- a/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc +++ b/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc @@ -18,7 +18,7 @@ NodeItem CombineXYZNodeParser::compute() NodeItem x = get_input_value("X", NodeItem::Type::Float); NodeItem y = get_input_value("Y", NodeItem::Type::Float); NodeItem z = get_input_value("Z", NodeItem::Type::Float); - NodeItem res = create_node("combine3", "vector3"); + NodeItem res = create_node("combine3", NodeItem::Type::Vector3); res.set_input("in1", x); res.set_input("in2", y); res.set_input("in3", z); diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index f039a6336e4..746cdab9803 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -14,12 +14,12 @@ NodeItem TexCheckerNodeParser::compute() NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); if (!vector) { - vector = create_node("texcoord", "vector2"); + vector = create_node("texcoord", NodeItem::Type::Vector2); } - vector = (vector * scale) % value(2.0f); + vector = (vector * scale) % val(2.0f); NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor()) - .if_else(NodeItem::CompareOp::Eq, value(1.0f), value(1.0f), value(0.0f)); - NodeItem res = create_node("mix", "color3"); + .if_else(NodeItem::CompareOp::Eq, val(1.0f), val(1.0f), val(0.0f)); + NodeItem res = create_node("mix", NodeItem::Type::Color3); res.set_input("fg", color1); res.set_input("bg", color2); res.set_input("mix", mix); diff --git a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc index f2aede4cb4b..97e5a61bbeb 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc @@ -23,9 +23,9 @@ NodeItem TexEnvironmentNodeParser::compute() image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); #endif - NodeItem texcoord = create_node("texcoord", "vector2"); - NodeItem res = create_node("image", "color3"); - res.set_input("file", image_path, "filename"); + NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2); + NodeItem res = create_node("image", NodeItem::Type::Color3); + res.set_input("file", image_path, NodeItem::Type::Filename); res.set_input("texcoord", texcoord); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc index 2a2625259ef..9ad1163aed5 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -23,9 +23,9 @@ NodeItem TexImageNodeParser::compute() image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); #endif - NodeItem texcoord = create_node("texcoord", "vector2"); - NodeItem res = create_node("image", "color3"); - res.set_input("file", image_path, "filename"); + NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2); + NodeItem res = create_node("image", NodeItem::Type::Color3); + res.set_input("file", image_path, NodeItem::Type::Filename); res.set_input("texcoord", texcoord); return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc index 60631acb4ff..ce6511b55d5 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc @@ -13,13 +13,13 @@ NodeItem TexNoiseNodeParser::compute() NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); if (detail.value && detail.type() == NodeItem::Type::Float) { - detail = value(int(detail.value->asA())); + detail = val(int(detail.value->asA())); } - NodeItem position = create_node("position", "vector3"); + NodeItem position = create_node("position", NodeItem::Type::Vector3); position = position * scale; - NodeItem res = create_node("fractal3d", "color3"); + NodeItem res = create_node("fractal3d", NodeItem::Type::Color3); res.set_input("position", position); res.set_input("octaves", detail); res.set_input("lacunarity", lacunarity); diff --git a/source/blender/nodes/shader/materialx/nodes/vector_math.cc b/source/blender/nodes/shader/materialx/nodes/vector_math.cc index a3267565772..51a6d6599f7 100644 --- a/source/blender/nodes/shader/materialx/nodes/vector_math.cc +++ b/source/blender/nodes/shader/materialx/nodes/vector_math.cc @@ -35,7 +35,7 @@ NodeItem VectorMathNodeParser::compute() res = x.ceil(); break; case NODE_VECTOR_MATH_FRACTION: - res = x % value(1.0f); + res = x % val(1.0f); break; case NODE_VECTOR_MATH_LENGTH: CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); -- 2.30.2 From 956df4e4db7fc3b88d06e090e3feb0aaf549ba02 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Fri, 8 Sep 2023 16:54:42 +0200 Subject: [PATCH 15/40] MaterialX: add convert nodes ### Purpose: Add support for convert nodes ### Technical steps: Added nodes: * clamp * RGB to BW * Blackbody * Map Range Pull Request: https://projects.blender.org/DagerD/blender/pulls/15 --- source/blender/nodes/shader/CMakeLists.txt | 8 ++- .../nodes/shader/materialx/nodes/blackbody.cc | 22 ++++++++ .../nodes/shader/materialx/nodes/clamp.cc | 27 ++++++++++ .../nodes/shader/materialx/nodes/map_range.cc | 51 +++++++++++++++++++ .../nodes/shader/materialx/nodes/node_item.cc | 8 +++ .../nodes/shader/materialx/nodes/node_item.h | 1 + .../shader/materialx/nodes/node_parser.cc | 4 ++ .../shader/materialx/nodes/node_parser.h | 4 ++ .../nodes/shader/materialx/nodes/rgb_to_bw.cc | 18 +++++++ 9 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/nodes/blackbody.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/clamp.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/map_range.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 1d75ad77a3d..d1e953629e8 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -148,6 +148,7 @@ if(WITH_MATERIALX) list(APPEND SRC materialx/material.cc materialx/nodes/add_shader.cc + materialx/nodes/blackbody.cc materialx/nodes/brightness.cc materialx/nodes/bsdf_diffuse.cc materialx/nodes/bsdf_glass.cc @@ -158,9 +159,11 @@ if(WITH_MATERIALX) materialx/nodes/bsdf_toon.cc materialx/nodes/bsdf_translucent.cc materialx/nodes/bsdf_transparent.cc + materialx/nodes/clamp.cc materialx/nodes/emission.cc materialx/nodes/huesatval.cc materialx/nodes/invert.cc + materialx/nodes/map_range.cc materialx/nodes/math.cc materialx/nodes/mix_rgb.cc materialx/nodes/mix_shader.cc @@ -168,15 +171,16 @@ if(WITH_MATERIALX) materialx/nodes/node_parser.cc materialx/nodes/normal_map.cc materialx/nodes/output_material.cc + materialx/nodes/rgb_to_bw.cc materialx/nodes/sepcomb_color.cc materialx/nodes/sepcomb_xyz.cc materialx/nodes/subsurface_scattering.cc materialx/nodes/tex_checker.cc materialx/nodes/tex_environment.cc materialx/nodes/tex_image.cc - materialx/nodes/tex_noise.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/blackbody.cc b/source/blender/nodes/shader/materialx/nodes/blackbody.cc new file mode 100644 index 00000000000..e3293ffe4fe --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/blackbody.cc @@ -0,0 +1,22 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem BlackbodyNodeParser::compute() +{ + /* This node doesn't have an implementation in MaterialX 1.38.6. + * It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8. + * + * NodeItem temperature = get_input_value("Temperature", NodeItem::Type::Float); + + * NodeItem res = create_node("blackbody", NodeItem::Type::Color3); + * res.set_input("temperature", temperature); + * return res; */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/clamp.cc b/source/blender/nodes/shader/materialx/nodes/clamp.cc new file mode 100644 index 00000000000..035a6dd9834 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/clamp.cc @@ -0,0 +1,27 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem ClampNodeParser::compute() +{ + auto type = node_->custom1; + NodeItem value = get_input_value("Value", NodeItem::Type::Float); + NodeItem min = get_input_value("Min", NodeItem::Type::Float); + NodeItem max = get_input_value("Max", NodeItem::Type::Float); + + NodeItem res = empty(); + if (type == NODE_CLAMP_RANGE) { + res = min.if_else( + NodeItem::CompareOp::Less, max, value.clamp(min, max), value.clamp(max, min)); + } + else { + res = value.clamp(min, max); + } + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/map_range.cc b/source/blender/nodes/shader/materialx/nodes/map_range.cc new file mode 100644 index 00000000000..a0ac1a6b223 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/map_range.cc @@ -0,0 +1,51 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem MapRangeNodeParser::compute() +{ + /* Interpolation isn't supported by MaterialX. */ + const NodeMapRange *map_range = static_cast(node_->storage); + + NodeItem::Type type; + NodeItem value = empty(); + NodeItem from_min = empty(); + NodeItem from_max = empty(); + NodeItem to_min = empty(); + NodeItem to_max = empty(); + switch (map_range->data_type) { + case CD_PROP_FLOAT: + type = NodeItem::Type::Float; + value = get_input_value("Value", type); + from_min = get_input_value(1, type); + from_max = get_input_value(2, type); + to_min = get_input_value(3, type); + to_max = get_input_value(4, type); + break; + case CD_PROP_FLOAT3: + type = NodeItem::Type::Vector3; + value = get_input_value("Vector", type); + from_min = get_input_value(7, type); + from_max = get_input_value(8, type); + to_min = get_input_value(9, type); + to_max = get_input_value(10, type); + break; + default: + BLI_assert_unreachable(); + } + + NodeItem res = create_node("range", type); + res.set_input("in", value); + res.set_input("inlow", from_min); + res.set_input("inhigh", from_max); + res.set_input("outlow", to_min); + res.set_input("outhigh", to_max); + res.set_input("doclamp", val(bool(map_range->clamp))); + 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 158a7178473..efef38cec1e 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -20,6 +20,9 @@ NodeItem::Type NodeItem::type(const std::string &type_str) if (type_str == "filename") { return Type::Filename; } + if (type_str == "boolean") { + return Type::Boolean; + } if (type_str == "integer") { return Type::Integer; } @@ -64,6 +67,8 @@ std::string NodeItem::type(Type type) return "string"; case Type::Filename: return "filename"; + case Type::Boolean: + return "boolean"; case Type::Integer: return "integer"; case Type::Float: @@ -633,6 +638,9 @@ void NodeItem::set_input(const std::string &in_name, const NodeItem &item) case Type::String: set_input(in_name, item.value->asA(), item_type); break; + case Type::Boolean: + set_input(in_name, item.value->asA(), item_type); + break; case Type::Integer: set_input(in_name, item.value->asA(), item_type); break; diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/nodes/node_item.h index 288dd70f3d5..f67adcd1113 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/nodes/node_item.h @@ -17,6 +17,7 @@ class NodeItem { /* Value types */ String, Filename, + Boolean, Integer, /* Block of arithmetic types. Ordered by type cast */ Float, diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 4a287932875..ec017a5319a 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -136,14 +136,18 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to break; switch (from_node->typeinfo->type) { + CASE_NODE_TYPE(SH_NODE_BLACKBODY, BlackbodyNodeParser) CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser) + CASE_NODE_TYPE(SH_NODE_CLAMP, ClampNodeParser) 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_MAP_RANGE, MapRangeNodeParser) 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_RGBTOBW, RGBToBWNodeParser) CASE_NODE_TYPE(SH_NODE_SEPARATE_COLOR, SeparateColorNodeParser) CASE_NODE_TYPE(SH_NODE_SEPXYZ, SeparateXYZNodeParser) CASE_NODE_TYPE(SH_NODE_TEX_CHECKER, TexCheckerNodeParser) diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index aed8803474c..9cfc729439c 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -90,14 +90,18 @@ template NodeItem NodeParser::val(const T &data) const NodeItem compute() override; \ }; +DECLARE_NODE_PARSER(BlackbodyNodeParser) DECLARE_NODE_PARSER(BrightContrastNodeParser) +DECLARE_NODE_PARSER(ClampNodeParser) DECLARE_NODE_PARSER(CombineColorNodeParser) DECLARE_NODE_PARSER(CombineXYZNodeParser) DECLARE_NODE_PARSER(HueSatValNodeParser) DECLARE_NODE_PARSER(InvertNodeParser) +DECLARE_NODE_PARSER(MapRangeNodeParser) DECLARE_NODE_PARSER(MathNodeParser) DECLARE_NODE_PARSER(MixRGBNodeParser) DECLARE_NODE_PARSER(NormalMapNodeParser) +DECLARE_NODE_PARSER(RGBToBWNodeParser) DECLARE_NODE_PARSER(SeparateColorNodeParser) DECLARE_NODE_PARSER(SeparateXYZNodeParser) DECLARE_NODE_PARSER(TexCheckerNodeParser) diff --git a/source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc b/source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc new file mode 100644 index 00000000000..26ed2469432 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc @@ -0,0 +1,18 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem RGBToBWNodeParser::compute() +{ + NodeItem color = get_input_value("Color", NodeItem::Type::Color4); + + NodeItem res = create_node("luminance", NodeItem::Type::Color4); + res.set_input("in", color); + return res; +} + +} // namespace blender::nodes::materialx -- 2.30.2 From 5e633f64e9db3418aa9b55d36ff339b2407cc609 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Fri, 8 Sep 2023 18:28:36 +0200 Subject: [PATCH 16/40] Export other channels and parameters from texture nodes ### Purpose Texture nodes has basic implementation without additional parameters and channels. ### Technical steps 1. Simplified and added `Fac` channel to TexChecker node 2. Fixed TexImage and TexEnvironment nodes: support alpha output, added params, image checking, TODOs. 3. Fix in Math node: moved to Float type. 4. Moved texture nodes to Color4. Pull Request: https://projects.blender.org/DagerD/blender/pulls/16 --- .../nodes/shader/materialx/nodes/math.cc | 10 ++- .../nodes/shader/materialx/nodes/node_item.cc | 18 ++--- .../shader/materialx/nodes/node_parser.cc | 13 ++++ .../shader/materialx/nodes/node_parser.h | 1 + .../shader/materialx/nodes/tex_checker.cc | 23 +++--- .../shader/materialx/nodes/tex_environment.cc | 44 +++++++++-- .../nodes/shader/materialx/nodes/tex_image.cc | 76 +++++++++++++++---- 7 files changed, 138 insertions(+), 47 deletions(-) diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index d7dd43cb004..9af8f665769 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -10,11 +10,13 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { /* TODO: finish some math operations */ - auto op = node_->custom1; + NodeMathOperation op = NodeMathOperation(node_->custom1); NodeItem res = empty(); /* Single operand operations */ - NodeItem x = get_input_value(0, NodeItem::Type::Any); + NodeItem x = get_input_value(0, NodeItem::Type::Float); + /* TODO: Seems we have to use average if Vector or Color are added */ + switch (op) { case NODE_MATH_SINE: res = x.sin(); @@ -82,7 +84,7 @@ NodeItem MathNodeParser::compute() default: { /* 2-operand operations */ - NodeItem y = get_input_value(1, NodeItem::Type::Any); + NodeItem y = get_input_value(1, NodeItem::Type::Float); switch (op) { case NODE_MATH_ADD: res = x + y; @@ -132,7 +134,7 @@ NodeItem MathNodeParser::compute() default: { /* 3-operand operations */ - NodeItem z = get_input_value(2, NodeItem::Type::Any); + NodeItem z = get_input_value(2, NodeItem::Type::Float); switch (op) { case NODE_MATH_WRAP: CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index efef38cec1e..f7fea7c2c9a 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -351,15 +351,6 @@ NodeItem NodeItem::exp() const return arithmetic("exp", [](float a) { return std::expf(a); }); } -NodeItem NodeItem::extract(const int index) const -{ - NodeItem res = empty(); - res = create_node("extract", Type::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(); @@ -605,6 +596,15 @@ NodeItem NodeItem::if_else(CompareOp op, return res; } +NodeItem NodeItem::extract(const int index) const +{ + NodeItem res = empty(); + res = create_node("extract", Type::Float); + res.set_input("in", *this); + res.set_input("index", val(index)); + return res; +} + NodeItem NodeItem::empty() const { return NodeItem(graph_); diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index ec017a5319a..4433852a4e7 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -9,6 +9,8 @@ namespace blender::nodes::materialx { +static const std::string TEXCOORD_NODE_NAME = "node_texcoord"; + NodeParser::NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, @@ -79,6 +81,17 @@ NodeItem NodeParser::empty() const return NodeItem(graph_); } +NodeItem NodeParser::texcoord_node() +{ + NodeItem res = empty(); + res.node = graph_->getNode(TEXCOORD_NODE_NAME); + if (!res.node) { + res = create_node("texcoord", NodeItem::Type::Vector2); + res.node->setName(TEXCOORD_NODE_NAME); + } + return res; +} + NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type) { NodeItem res = empty(); diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 9cfc729439c..d23471db8c0 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -42,6 +42,7 @@ class NodeParser { NodeItem get_input_value(int index, NodeItem::Type to_type); NodeItem empty() const; template NodeItem val(const T &data) const; + NodeItem texcoord_node(); private: NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index 746cdab9803..1d58e0e14a8 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -9,21 +9,20 @@ namespace blender::nodes::materialx { NodeItem TexCheckerNodeParser::compute() { NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); - NodeItem color1 = get_input_value("Color1", NodeItem::Type::Color3); - NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3); + if (!vector) { + vector = texcoord_node(); + } + NodeItem value1 = val(1.0f); + NodeItem value2 = val(0.0f); + if (STREQ(socket_out_->name, "Color")) { + value1 = get_input_value("Color1", NodeItem::Type::Color4); + value2 = get_input_value("Color2", NodeItem::Type::Color4); + } NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); - if (!vector) { - vector = create_node("texcoord", NodeItem::Type::Vector2); - } vector = (vector * scale) % val(2.0f); - NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor()) - .if_else(NodeItem::CompareOp::Eq, val(1.0f), val(1.0f), val(0.0f)); - NodeItem res = create_node("mix", NodeItem::Type::Color3); - res.set_input("fg", color1); - res.set_input("bg", color2); - res.set_input("mix", mix); - return res; + return (vector.extract(0).floor() + vector.extract(1).floor()) + .if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc index 97e5a61bbeb..65b5c451559 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc @@ -12,21 +12,49 @@ namespace blender::nodes::materialx { NodeItem TexEnvironmentNodeParser::compute() { + NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); + Image *image = (Image *)node_->id; - NodeTexEnvironment *tex = static_cast(node_->storage); + if (!image) { + return res; + } + + NodeTexEnvironment *tex_env = static_cast(node_->storage); Scene *scene = DEG_get_input_scene(depsgraph_); Main *bmain = DEG_get_bmain(depsgraph_); - std::string image_path; + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains * pretty general code, so could be moved from bf_usd project. */ -#ifdef WITH_HYDRA - image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); -#endif + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_env->iuser); - NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2); - NodeItem res = create_node("image", NodeItem::Type::Color3); + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: texcoords should be translated to spherical coordinates */ + + std::string filtertype; + switch (tex_env->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", texcoord); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc index 9ad1163aed5..75c30a0a045 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -12,21 +12,69 @@ namespace blender::nodes::materialx { NodeItem TexImageNodeParser::compute() { - Image *image = (Image *)node_->id; - NodeTexImage *tex = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); - std::string image_path; - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains - * pretty general code, so could be moved from bf_usd project. */ -#ifdef WITH_HYDRA - image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); -#endif + NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); - NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2); - NodeItem res = create_node("image", NodeItem::Type::Color3); - res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", texcoord); + Image *image = (Image *)node_->id; + if (image) { + NodeTexImage *tex_image = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); + + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains + * pretty general code, so could be moved from bf_usd project. */ + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_image->iuser); + + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: add math to vector depending of tex_image->projection */ + + std::string filtertype; + switch (tex_image->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + std::string addressmode; + switch (tex_image->extension) { + case SHD_IMAGE_EXTENSION_REPEAT: + addressmode = "periodic"; + break; + case SHD_IMAGE_EXTENSION_EXTEND: + addressmode = "clamp"; + break; + case SHD_IMAGE_EXTENSION_CLIP: + addressmode = "constant"; + break; + case SHD_IMAGE_EXTENSION_MIRROR: + addressmode = "mirror"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); + res.set_input("file", image_path, NodeItem::Type::Filename); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + res.set_input("uaddressmode", val(addressmode)); + res.set_input("vaddressmode", val(addressmode)); + } + + if (STREQ(socket_out_->name, "Alpha")) { + res = res.extract(3); + } return res; } -- 2.30.2 From 14ab54453f39125fc0e7b87ab2d0413beaad3c91 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Mon, 11 Sep 2023 18:56:45 +0200 Subject: [PATCH 17/40] MaterialX: add color nodes ### Purpose Add support for Color nodes ### Technical steps Added: * Gamma Partially implemented: * Light Falloff * Light Path Not implemented: * Color Ramp * Curves Float * Curves RGB * Wavelength Pull Request: https://projects.blender.org/blender/blender/pulls/17 --- source/blender/nodes/shader/CMakeLists.txt | 6 ++++++ .../shader/materialx/nodes/color_ramp.cc | 15 +++++++++++++ .../nodes/shader/materialx/nodes/curves.cc | 21 +++++++++++++++++++ .../nodes/shader/materialx/nodes/gamma.cc | 17 +++++++++++++++ .../shader/materialx/nodes/light_falloff.cc | 21 +++++++++++++++++++ .../shader/materialx/nodes/light_path.cc | 21 +++++++++++++++++++ .../shader/materialx/nodes/node_parser.cc | 7 +++++++ .../shader/materialx/nodes/node_parser.h | 7 +++++++ .../shader/materialx/nodes/wavelength.cc | 15 +++++++++++++ 9 files changed, 130 insertions(+) create mode 100644 source/blender/nodes/shader/materialx/nodes/color_ramp.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/curves.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/gamma.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/light_falloff.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/light_path.cc create mode 100644 source/blender/nodes/shader/materialx/nodes/wavelength.cc diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index d1e953629e8..0d37eb5f5bd 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -160,9 +160,14 @@ if(WITH_MATERIALX) materialx/nodes/bsdf_translucent.cc materialx/nodes/bsdf_transparent.cc materialx/nodes/clamp.cc + materialx/nodes/color_ramp.cc + materialx/nodes/curves.cc + materialx/nodes/gamma.cc materialx/nodes/emission.cc materialx/nodes/huesatval.cc materialx/nodes/invert.cc + materialx/nodes/light_falloff.cc + materialx/nodes/light_path.cc materialx/nodes/map_range.cc materialx/nodes/math.cc materialx/nodes/mix_rgb.cc @@ -180,6 +185,7 @@ if(WITH_MATERIALX) materialx/nodes/tex_image.cc materialx/nodes/tex_noise.cc materialx/nodes/vector_math.cc + materialx/nodes/wavelength.cc materialx/material.h materialx/nodes/node_item.h diff --git a/source/blender/nodes/shader/materialx/nodes/color_ramp.cc b/source/blender/nodes/shader/materialx/nodes/color_ramp.cc new file mode 100644 index 00000000000..b95f272c21c --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/color_ramp.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem ColorRampNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/curves.cc b/source/blender/nodes/shader/materialx/nodes/curves.cc new file mode 100644 index 00000000000..e8ff16f6e80 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/curves.cc @@ -0,0 +1,21 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem CurvesRGBNodeParser::compute() +{ + /* TODO: implement */ + return get_input_value("Color", NodeItem::Type::Color4); +} + +NodeItem CurvesFloatNodeParser::compute() +{ + /* TODO: implement */ + return get_input_value("Value", NodeItem::Type::Float); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/gamma.cc b/source/blender/nodes/shader/materialx/nodes/gamma.cc new file mode 100644 index 00000000000..ef4b88e0594 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/gamma.cc @@ -0,0 +1,17 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem GammaNodeParser::compute() +{ + NodeItem color = get_input_value("Color", NodeItem::Type::Color4); + NodeItem gamma = get_input_value("Gamma", NodeItem::Type::Float); + + return color ^ gamma; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/light_falloff.cc b/source/blender/nodes/shader/materialx/nodes/light_falloff.cc new file mode 100644 index 00000000000..81186747540 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/light_falloff.cc @@ -0,0 +1,21 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem LightFalloffNodeParser::compute() +{ + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); + NodeItem smooth = get_input_value("Smooth", NodeItem::Type::Float); + + /* This node isn't supported by MaterialX. This formula was given from OSL shader code in Cycles + * node_light_falloff.osl. Considered ray_length=1.0f. */ + strength = strength * val(1.0f) / (smooth + val(1.0f)); + + return strength; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/light_path.cc b/source/blender/nodes/shader/materialx/nodes/light_path.cc new file mode 100644 index 00000000000..0c58f89d6bf --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/light_path.cc @@ -0,0 +1,21 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem LightPathNodeParser::compute() +{ + /* This node isn't supported by MaterialX. Only default values returned. */ + if (STREQ(socket_out_->name, "Is Camera Ray")) { + return val(1.0f); + } + if (STREQ(socket_out_->name, "Ray Length")) { + return val(1.0f); + } + return val(0.0f); +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index 4433852a4e7..f68ec48949d 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -152,10 +152,16 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to CASE_NODE_TYPE(SH_NODE_BLACKBODY, BlackbodyNodeParser) CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser) CASE_NODE_TYPE(SH_NODE_CLAMP, ClampNodeParser) + CASE_NODE_TYPE(SH_NODE_VALTORGB, ColorRampNodeParser) + CASE_NODE_TYPE(SH_NODE_CURVE_FLOAT, CurvesFloatNodeParser) + CASE_NODE_TYPE(SH_NODE_CURVE_RGB, CurvesRGBNodeParser) + CASE_NODE_TYPE(SH_NODE_GAMMA, GammaNodeParser) 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_LIGHT_FALLOFF, LightFalloffNodeParser) + CASE_NODE_TYPE(SH_NODE_LIGHT_PATH, LightPathNodeParser) CASE_NODE_TYPE(SH_NODE_MAP_RANGE, MapRangeNodeParser) CASE_NODE_TYPE(SH_NODE_MATH, MathNodeParser) CASE_NODE_TYPE(SH_NODE_MIX_RGB_LEGACY, MixRGBNodeParser) @@ -168,6 +174,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to CASE_NODE_TYPE(SH_NODE_TEX_IMAGE, TexImageNodeParser) CASE_NODE_TYPE(SH_NODE_TEX_NOISE, TexNoiseNodeParser) CASE_NODE_TYPE(SH_NODE_VECTOR_MATH, VectorMathNodeParser) + CASE_NODE_TYPE(SH_NODE_WAVELENGTH, WavelengthNodeParser) 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 d23471db8c0..a327352629f 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -94,10 +94,16 @@ template NodeItem NodeParser::val(const T &data) const DECLARE_NODE_PARSER(BlackbodyNodeParser) DECLARE_NODE_PARSER(BrightContrastNodeParser) DECLARE_NODE_PARSER(ClampNodeParser) +DECLARE_NODE_PARSER(ColorRampNodeParser) +DECLARE_NODE_PARSER(CurvesFloatNodeParser) +DECLARE_NODE_PARSER(CurvesRGBNodeParser) DECLARE_NODE_PARSER(CombineColorNodeParser) DECLARE_NODE_PARSER(CombineXYZNodeParser) +DECLARE_NODE_PARSER(GammaNodeParser) DECLARE_NODE_PARSER(HueSatValNodeParser) DECLARE_NODE_PARSER(InvertNodeParser) +DECLARE_NODE_PARSER(LightFalloffNodeParser) +DECLARE_NODE_PARSER(LightPathNodeParser) DECLARE_NODE_PARSER(MapRangeNodeParser) DECLARE_NODE_PARSER(MathNodeParser) DECLARE_NODE_PARSER(MixRGBNodeParser) @@ -110,6 +116,7 @@ DECLARE_NODE_PARSER(TexEnvironmentNodeParser) DECLARE_NODE_PARSER(TexImageNodeParser) DECLARE_NODE_PARSER(TexNoiseNodeParser) DECLARE_NODE_PARSER(VectorMathNodeParser) +DECLARE_NODE_PARSER(WavelengthNodeParser) DECLARE_SHADER_NODE_PARSER(AddShaderNodeParser) DECLARE_SHADER_NODE_PARSER(BSDFDiffuseNodeParser) diff --git a/source/blender/nodes/shader/materialx/nodes/wavelength.cc b/source/blender/nodes/shader/materialx/nodes/wavelength.cc new file mode 100644 index 00000000000..892504e1727 --- /dev/null +++ b/source/blender/nodes/shader/materialx/nodes/wavelength.cc @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +namespace blender::nodes::materialx { + +NodeItem WavelengthNodeParser::compute() +{ + /* TODO: implement */ + return empty(); +} + +} // namespace blender::nodes::materialx -- 2.30.2 From 9e483eace312ba25991589894061fff926101f7c Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 12 Sep 2023 13:55:04 +0200 Subject: [PATCH 18/40] Move the MaterialX export code into the existing shader node files ### Purpose Due to review suggestions, MaterialX export code should be moved to existing node files. ### Technical steps 1. Added `bNodeType::materialx_fn` function pointer. 2. Created special macroses `NODE_SHADER_MATERIALX_BEGIN`, `NODE_SHADER_MATERIALX_END` for including MaterialX export code into `node_shader_.cc` files. 3. Removed `ShaderNodeParser` as not needed, just `NodeParser` can be used. Adjusted `get_input_link()` to work with shader types. Made `get_input_link()` to call `materialx_fn`. 4. Moved `node_parser.cc/.h`, `node_item.cc/.h` to `materialx` folder. 5. Moved MaterialX node export implementation to corresponded `node_shader_.cc` files. Removed `materialx/nodes/...` files. 6. Created `DefaultMaterialNodeParser` in `material.cc`. Pull Request: https://projects.blender.org/DagerD/blender/pulls/18 --- source/blender/blenkernel/BKE_node.h | 5 + source/blender/nodes/shader/CMakeLists.txt | 46 +-- .../nodes/shader/materialx/material.cc | 54 ++- .../blender/nodes/shader/materialx/material.h | 4 - .../shader/materialx/{nodes => }/node_item.cc | 3 +- .../shader/materialx/{nodes => }/node_item.h | 2 +- .../nodes/shader/materialx/node_parser.cc | 188 +++++++++++ .../nodes/shader/materialx/node_parser.h | 96 ++++++ .../shader/materialx/nodes/add_shader.cc | 42 --- .../nodes/shader/materialx/nodes/blackbody.cc | 22 -- .../shader/materialx/nodes/brightness.cc | 19 -- .../shader/materialx/nodes/bsdf_diffuse.cc | 28 -- .../shader/materialx/nodes/bsdf_glass.cc | 15 - .../shader/materialx/nodes/bsdf_glossy.cc | 15 - .../shader/materialx/nodes/bsdf_principled.cc | 101 ------ .../shader/materialx/nodes/bsdf_refraction.cc | 15 - .../shader/materialx/nodes/bsdf_sheen.cc | 15 - .../nodes/shader/materialx/nodes/bsdf_toon.cc | 15 - .../materialx/nodes/bsdf_translucent.cc | 15 - .../materialx/nodes/bsdf_transparent.cc | 15 - .../nodes/shader/materialx/nodes/clamp.cc | 27 -- .../shader/materialx/nodes/color_ramp.cc | 15 - .../nodes/shader/materialx/nodes/curves.cc | 21 -- .../nodes/shader/materialx/nodes/emission.cc | 23 -- .../nodes/shader/materialx/nodes/gamma.cc | 17 - .../nodes/shader/materialx/nodes/huesatval.cc | 33 -- .../nodes/shader/materialx/nodes/invert.cc | 16 - .../shader/materialx/nodes/light_falloff.cc | 21 -- .../shader/materialx/nodes/light_path.cc | 21 -- .../nodes/shader/materialx/nodes/map_range.cc | 51 --- .../nodes/shader/materialx/nodes/math.cc | 171 ---------- .../nodes/shader/materialx/nodes/mix_rgb.cc | 15 - .../shader/materialx/nodes/mix_shader.cc | 46 --- .../shader/materialx/nodes/node_parser.cc | 318 ------------------ .../shader/materialx/nodes/node_parser.h | 135 -------- .../shader/materialx/nodes/normal_map.cc | 40 --- .../shader/materialx/nodes/output_material.cc | 70 ---- .../shader/materialx/nodes/output_material.h | 26 -- .../nodes/shader/materialx/nodes/rgb_to_bw.cc | 18 - .../shader/materialx/nodes/sepcomb_color.cc | 72 ---- .../shader/materialx/nodes/sepcomb_xyz.cc | 28 -- .../materialx/nodes/subsurface_scattering.cc | 15 - .../shader/materialx/nodes/tex_checker.cc | 28 -- .../shader/materialx/nodes/tex_environment.cc | 61 ---- .../nodes/shader/materialx/nodes/tex_image.cc | 81 ----- .../nodes/shader/materialx/nodes/tex_noise.cc | 29 -- .../shader/materialx/nodes/vector_math.cc | 122 ------- .../shader/materialx/nodes/wavelength.cc | 15 - .../blender/nodes/shader/node_shader_util.hh | 2 + .../shader/nodes/node_shader_add_shader.cc | 35 ++ .../shader/nodes/node_shader_blackbody.cc | 15 + .../shader/nodes/node_shader_brightness.cc | 12 + .../shader/nodes/node_shader_bsdf_diffuse.cc | 21 ++ .../nodes/node_shader_bsdf_principled.cc | 94 ++++++ .../nodes/shader/nodes/node_shader_clamp.cc | 20 ++ .../shader/nodes/node_shader_color_ramp.cc | 8 + .../nodes/shader/nodes/node_shader_curves.cc | 42 ++- .../shader/nodes/node_shader_emission.cc | 16 + .../nodes/shader/nodes/node_shader_gamma.cc | 8 + .../shader/nodes/node_shader_hueSatVal.cc | 25 ++ .../nodes/shader/nodes/node_shader_invert.cc | 9 + .../shader/nodes/node_shader_light_falloff.cc | 12 + .../shader/nodes/node_shader_light_path.cc | 14 + .../shader/nodes/node_shader_map_range.cc | 44 +++ .../nodes/shader/nodes/node_shader_math.cc | 165 +++++++++ .../nodes/shader/nodes/node_shader_mix_rgb.cc | 8 + .../shader/nodes/node_shader_mix_shader.cc | 40 +++ .../shader/nodes/node_shader_normal_map.cc | 33 ++ .../nodes/node_shader_output_material.cc | 24 ++ .../shader/nodes/node_shader_rgb_to_bw.cc | 11 + .../shader/nodes/node_shader_sepcomb_color.cc | 57 ++++ .../shader/nodes/node_shader_sepcomb_xyz.cc | 36 +- .../shader/nodes/node_shader_tex_checker.cc | 21 ++ .../nodes/node_shader_tex_environment.cc | 8 + .../shader/nodes/node_shader_tex_image.cc | 74 ++++ .../shader/nodes/node_shader_tex_noise.cc | 20 ++ .../shader/nodes/node_shader_vector_math.cc | 116 +++++++ 77 files changed, 1321 insertions(+), 1919 deletions(-) rename source/blender/nodes/shader/materialx/{nodes => }/node_item.cc (99%) rename source/blender/nodes/shader/materialx/{nodes => }/node_item.h (100%) create mode 100644 source/blender/nodes/shader/materialx/node_parser.cc create mode 100644 source/blender/nodes/shader/materialx/node_parser.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/add_shader.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/blackbody.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/brightness.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/clamp.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/color_ramp.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/curves.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/emission.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/gamma.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/huesatval.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/invert.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/light_falloff.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/light_path.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/map_range.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/math.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/mix_rgb.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/mix_shader.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/node_parser.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/node_parser.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/normal_map.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/output_material.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/output_material.h delete mode 100644 source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/tex_checker.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/tex_environment.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/tex_image.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/tex_noise.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/vector_math.cc delete mode 100644 source/blender/nodes/shader/materialx/nodes/wavelength.cc diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 129453f7c1b..e14067f138e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -225,6 +225,9 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, struct bNodeExecData *execdata, struct GPUNodeStack *in, struct GPUNodeStack *out); +typedef void (*NodeMaterialXExecFunction)(void *data, + struct bNode *node, + struct bNodeSocket *out); /** * \brief Defines a node type. @@ -339,6 +342,8 @@ typedef struct bNodeType { NodeExecFunction exec_fn; /* gpu */ NodeGPUExecFunction gpu_fn; + /* MaterialX */ + NodeMaterialXExecFunction materialx_fn; /* Get an instance of this node's compositor operation. Freeing the instance is the * responsibility of the caller. */ diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 0d37eb5f5bd..98e9f7db99a 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -147,50 +147,12 @@ set(LIB if(WITH_MATERIALX) list(APPEND SRC materialx/material.cc - materialx/nodes/add_shader.cc - materialx/nodes/blackbody.cc - materialx/nodes/brightness.cc - materialx/nodes/bsdf_diffuse.cc - materialx/nodes/bsdf_glass.cc - materialx/nodes/bsdf_glossy.cc - materialx/nodes/bsdf_principled.cc - materialx/nodes/bsdf_refraction.cc - materialx/nodes/bsdf_sheen.cc - materialx/nodes/bsdf_toon.cc - materialx/nodes/bsdf_translucent.cc - materialx/nodes/bsdf_transparent.cc - materialx/nodes/clamp.cc - materialx/nodes/color_ramp.cc - materialx/nodes/curves.cc - materialx/nodes/gamma.cc - materialx/nodes/emission.cc - materialx/nodes/huesatval.cc - materialx/nodes/invert.cc - materialx/nodes/light_falloff.cc - materialx/nodes/light_path.cc - materialx/nodes/map_range.cc - materialx/nodes/math.cc - materialx/nodes/mix_rgb.cc - materialx/nodes/mix_shader.cc - materialx/nodes/node_item.cc - materialx/nodes/node_parser.cc - materialx/nodes/normal_map.cc - materialx/nodes/output_material.cc - materialx/nodes/rgb_to_bw.cc - materialx/nodes/sepcomb_color.cc - materialx/nodes/sepcomb_xyz.cc - materialx/nodes/subsurface_scattering.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/nodes/wavelength.cc + materialx/node_item.cc + materialx/node_parser.cc materialx/material.h - materialx/nodes/node_item.h - materialx/nodes/node_parser.h - materialx/nodes/output_material.h + materialx/node_item.h + materialx/node_parser.h ) list(APPEND LIB MaterialXCore diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 1902d1dc2f5..540204a8d87 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -3,7 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "material.h" -#include "nodes/output_material.h" +#include "node_parser.h" #include @@ -15,7 +15,42 @@ namespace blender::nodes::materialx { -CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader"); +class DefaultMaterialNodeParser : public NodeParser { + public: + using NodeParser::NodeParser; + + NodeItem compute() override + { + NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); + surface.set_input("base_color", + val(MaterialX::Color3(material_->r, material_->g, material_->b))); + surface.set_input("diffuse_roughness", val(material_->roughness)); + if (material_->metallic > 0.0f) { + surface.set_input("metalness", val(material_->metallic)); + } + if (material_->spec) { + surface.set_input("specular", val(material_->spec)); + surface.set_input("specular_color", val(material_->spec)); + surface.set_input("specular_roughness", val(material_->roughness)); + } + + NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); + res.node->setName("Material_Default"); + res.set_input("surfaceshader", surface); + return res; + } + + NodeItem compute_error() + { + NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); + surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f))); + + NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); + res.node->setName("Material_Error"); + res.set_input("surfaceshader", surface); + return res; + } +}; MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material) { @@ -25,10 +60,21 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater if (material->use_nodes) { material->nodetree->ensure_topology_cache(); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); - OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute_full(); + if (output_node) { + NodeParserData data = { + doc.get(), depsgraph, material, NodeItem::Type::Material, NodeItem(doc.get())}; + output_node->typeinfo->materialx_fn(&data, output_node, nullptr); + } + else { + DefaultMaterialNodeParser( + doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material) + .compute_error(); + } } else { - OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default(); + DefaultMaterialNodeParser( + doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material) + .compute(); } CLOG_INFO(LOG_MATERIALX_SHADER, diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h index b32f3ff2962..760b6cdef33 100644 --- a/source/blender/nodes/shader/materialx/material.h +++ b/source/blender/nodes/shader/materialx/material.h @@ -6,15 +6,11 @@ #include -#include "CLG_log.h" - struct Depsgraph; struct Material; namespace blender::nodes::materialx { -extern struct CLG_LogRef *LOG_MATERIALX_SHADER; - MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc similarity index 99% rename from source/blender/nodes/shader/materialx/nodes/node_item.cc rename to source/blender/nodes/shader/materialx/node_item.cc index f7fea7c2c9a..af3d6af54f6 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -3,7 +3,6 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "node_item.h" -#include "../material.h" #include "BLI_assert.h" #include "BLI_utildefines.h" @@ -63,6 +62,8 @@ NodeItem::Type NodeItem::type(const std::string &type_str) std::string NodeItem::type(Type type) { switch (type) { + case Type::Any: + return ""; case Type::String: return "string"; case Type::Filename: diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.h b/source/blender/nodes/shader/materialx/node_item.h similarity index 100% rename from source/blender/nodes/shader/materialx/nodes/node_item.h rename to source/blender/nodes/shader/materialx/node_item.h index f67adcd1113..f9e45822f66 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -50,6 +50,7 @@ class NodeItem { static Type type(const std::string &type_str); static std::string type(Type type); + static bool is_arithmetic(Type type); /* Operators */ operator bool() const; @@ -109,7 +110,6 @@ class NodeItem { void add_output(const std::string &in_name, Type out_type); private: - static bool is_arithmetic(Type type); static Type cast_types(NodeItem &item1, NodeItem &item2); bool is_arithmetic() const; diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc new file mode 100644 index 00000000000..357a27cacbb --- /dev/null +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -0,0 +1,188 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_parser.h" + +#include "BKE_node_runtime.hh" + +namespace blender::nodes::materialx { + +static const std::string TEXCOORD_NODE_NAME = "node_texcoord"; + +CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader"); + +NodeParser::NodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node, + const bNodeSocket *socket_out, + NodeItem::Type to_type) + : graph_(graph), + depsgraph_(depsgraph), + material_(material), + node_(node), + socket_out_(socket_out), + to_type_(to_type) +{ +} + +NodeItem NodeParser::compute_full() +{ + NodeItem res = empty(); + + /* Checking if node was already computed */ + res.node = graph_->getNode(node_name()); + if (res.node) { + return res; + } + + CLOG_INFO(LOG_MATERIALX_SHADER, + 1, + "%s [%d] => %s", + node_->name, + node_->typeinfo->type, + NodeItem::type(to_type_).c_str()); + + res = compute(); + if (res.node) { + res.node->setName(node_name()); + } + if (NodeItem::is_arithmetic(to_type_)) { + res = res.convert(to_type_); + } + return res; +} + +std::string NodeParser::node_name() +{ + std::string name = node_->name; + if (node_->output_sockets().size() > 1) { + name += std::string("_") + socket_out_->name; + } + if (ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { + name += "_" + NodeItem::type(to_type_); + } + return MaterialX::createValidName(name); +} + +NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type) +{ + return empty().create_node(category, type); +} + +NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) +{ + return get_input_default(node_->input_by_identifier(name), to_type); +} + +NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type) +{ + return get_input_default(node_->input_socket(index), to_type); +} + +NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type) +{ + return get_input_link(node_->input_by_identifier(name), to_type); +} + +NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type) +{ + return get_input_link(node_->input_socket(index), to_type); +} + +NodeItem NodeParser::get_input_value(const std::string &name, NodeItem::Type to_type) +{ + return get_input_value(node_->input_by_identifier(name), to_type); +} + +NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type) +{ + return get_input_value(node_->input_socket(index), to_type); +} + +NodeItem NodeParser::empty() const +{ + return NodeItem(graph_); +} + +NodeItem NodeParser::texcoord_node() +{ + NodeItem res = empty(); + res.node = graph_->getNode(TEXCOORD_NODE_NAME); + if (!res.node) { + res = create_node("texcoord", NodeItem::Type::Vector2); + res.node->setName(TEXCOORD_NODE_NAME); + } + return res; +} + +NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type) +{ + NodeItem res = empty(); + switch (socket.type) { + case SOCK_FLOAT: { + float v = socket.default_value_typed()->value; + res.value = MaterialX::Value::createValue(v); + break; + } + case SOCK_VECTOR: { + const float *v = socket.default_value_typed()->value; + res.value = MaterialX::Value::createValue( + MaterialX::Vector3(v[0], v[1], v[2])); + break; + } + case SOCK_RGBA: { + const float *v = socket.default_value_typed()->value; + res.value = MaterialX::Value::createValue( + MaterialX::Color4(v[0], v[1], v[2], v[3])); + break; + } + default: { + CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type); + } + } + return res.convert(to_type); +} + +NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to_type) +{ + const bNodeLink *link = socket.link; + if (!(link && link->is_used())) { + return empty(); + } + + const bNode *from_node = link->fromnode; + + /* Passing NODE_REROUTE nodes */ + while (from_node->type == NODE_REROUTE) { + link = from_node->input_socket(0).link; + if (!(link && link->is_used())) { + return empty(); + } + from_node = link->fromnode; + } + + if (!from_node->typeinfo->materialx_fn) { + CLOG_WARN(LOG_MATERIALX_SHADER, + "Unsupported node: %s [%d]", + from_node->name, + from_node->typeinfo->type); + return empty(); + } + + NodeParserData data = {graph_, depsgraph_, material_, to_type, empty()}; + from_node->typeinfo->materialx_fn(&data, const_cast(from_node), link->fromsock); + return data.result; +} + +NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type to_type) +{ + NodeItem res = get_input_link(socket, to_type); + if (!res) { + res = get_input_default(socket, to_type); + } + return res; +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h new file mode 100644 index 00000000000..c0e6d6952f0 --- /dev/null +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -0,0 +1,96 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node_item.h" + +#include "DEG_depsgraph.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" + +#include "CLG_log.h" + +namespace blender::nodes::materialx { + +extern struct CLG_LogRef *LOG_MATERIALX_SHADER; + +class NodeParser { + protected: + MaterialX::GraphElement *graph_; + const Depsgraph *depsgraph_; + const Material *material_; + const bNode *node_; + const bNodeSocket *socket_out_; + NodeItem::Type to_type_; + + public: + NodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node, + const bNodeSocket *socket_out, + NodeItem::Type to_type); + virtual ~NodeParser() = default; + + virtual NodeItem compute() = 0; + virtual NodeItem compute_full(); + + protected: + std::string node_name(); + NodeItem create_node(const std::string &category, NodeItem::Type type); + NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); + NodeItem get_input_default(int index, NodeItem::Type to_type); + NodeItem get_input_link(const std::string &name, NodeItem::Type to_type); + NodeItem get_input_link(int index, NodeItem::Type to_type); + NodeItem get_input_value(const std::string &name, NodeItem::Type to_type); + NodeItem get_input_value(int index, NodeItem::Type to_type); + NodeItem empty() const; + template NodeItem val(const T &data) const; + NodeItem texcoord_node(); + + private: + NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); + NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type); + NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type); +}; + +template NodeItem NodeParser::val(const T &data) const +{ + return empty().val(data); +} + +/* + * Defines for including MaterialX node parsing code into node_shader_.cc + */ +struct NodeParserData { + MaterialX::GraphElement *graph; + const Depsgraph *depsgraph; + const Material *material; + NodeItem::Type to_type; + NodeItem result; +}; + +#define NODE_SHADER_MATERIALX_BEGIN \ + class MaterialXNodeParser : public materialx::NodeParser { \ + public: \ + using materialx::NodeParser::NodeParser; \ + materialx::NodeItem compute() override; \ + }; \ +\ + materialx::NodeItem MaterialXNodeParser::compute() \ + { \ + using NodeItem = materialx::NodeItem; + +#define NODE_SHADER_MATERIALX_END \ + } \ +\ + void node_shader_materialx(void *data, struct bNode *node, struct bNodeSocket *out) \ + { \ + materialx::NodeParserData *d = reinterpret_cast(data); \ + d->result = MaterialXNodeParser(d->graph, d->depsgraph, d->material, node, out, d->to_type) \ + .compute_full(); \ + } + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/add_shader.cc b/source/blender/nodes/shader/materialx/nodes/add_shader.cc deleted file mode 100644 index 8ac9d7ab4c2..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/add_shader.cc +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem AddShaderNodeParser::compute() -{ - NodeItem res = empty(); - switch (shader_type_) { - case NodeItem::Type::BSDF: - case NodeItem::Type::EDF: { - NodeItem shader1 = get_input_shader(0, shader_type_); - NodeItem shader2 = get_input_shader(1, shader_type_); - - if (shader1 && !shader2) { - res = shader1; - } - else if (!shader1 && shader2) { - res = shader2; - } - else if (shader1 && shader2) { - res = shader1 + shader2; - } - break; - } - case NodeItem::Type::SurfaceShader: { - res = get_input_shader(0, shader_type_); - if (!res) { - res = get_input_shader(1, shader_type_); - } - break; - } - default: - BLI_assert_unreachable(); - } - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/blackbody.cc b/source/blender/nodes/shader/materialx/nodes/blackbody.cc deleted file mode 100644 index e3293ffe4fe..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/blackbody.cc +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BlackbodyNodeParser::compute() -{ - /* This node doesn't have an implementation in MaterialX 1.38.6. - * It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8. - * - * NodeItem temperature = get_input_value("Temperature", NodeItem::Type::Float); - - * NodeItem res = create_node("blackbody", NodeItem::Type::Color3); - * res.set_input("temperature", temperature); - * return res; */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/brightness.cc b/source/blender/nodes/shader/materialx/nodes/brightness.cc deleted file mode 100644 index 01beec5ca38..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/brightness.cc +++ /dev/null @@ -1,19 +0,0 @@ -/* 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::Type::Color3); - NodeItem bright = get_input_value("Bright", NodeItem::Type::Float); - NodeItem contrast = get_input_value("Contrast", NodeItem::Type::Float); - - /* This formula was given from OSL shader code in Cycles. */ - return (bright + color * (contrast + val(1.0f)) - contrast * val(0.5f)).max(val(0.0f)); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc deleted file mode 100644 index 7ef11fb9bbc..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFDiffuseNodeParser::compute() -{ - if (shader_type_ != NodeItem::Type::BSDF) { - return empty(); - } - - NodeItem color = get_input_value("Color", NodeItem::Type::Color3); - NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); - NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - - NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF); - res.set_input("color", color); - res.set_input("roughness", roughness); - if (normal) { - res.set_input("normal", normal); - } - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc deleted file mode 100644 index 092953e7eed..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFGlassNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc deleted file mode 100644 index 98a372ec14c..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFGlossyNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // 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 deleted file mode 100644 index 7ce0b153b31..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_principled.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFPrincipledNodeParser::compute() -{ - if (shader_type_ != NodeItem::Type::SurfaceShader) { - /* TODO: implement for BSDF and EDF */ - return empty(); - } - - NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3); - - NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float); - NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3); - NodeItem subsurface_color = get_input_value("Subsurface Color", NodeItem::Type::Color3); - - NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float); - NodeItem specular = get_input_value("Specular", NodeItem::Type::Float); - // NodeItem specular_tint = get_input_value("Specular Tint"); - NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); - - /* TODO: use Specular Tint input */ - NodeItem anisotropic = get_input_value("Anisotropic", NodeItem::Type::Float); - NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation", NodeItem::Type::Float); - // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) - - NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float); - // sheen_tint = get_input_value("Sheen Tint"); - - NodeItem clearcoat = get_input_value("Clearcoat", NodeItem::Type::Float); - NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness", NodeItem::Type::Float); - - NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); - - NodeItem transmission = get_input_value("Transmission", NodeItem::Type::Float); - - NodeItem emission = get_input_value("Emission", NodeItem::Type::Color3); - NodeItem emission_strength = get_input_value("Emission Strength", NodeItem::Type::Float); - - NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float); - // transparency = 1.0 - alpha - - NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3); - NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); - - /* Creating standard_surface */ - NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader); - res.set_input("base", val(1.0f)); - res.set_input("base_color", base_color); - res.set_input("diffuse_roughness", roughness); - if (normal) { - res.set_input("normal", normal); - } - if (tangent) { - res.set_input("tangent", tangent); - } - res.set_input("metalness", metallic); - - res.set_input("specular", specular); - res.set_input("specular_color", base_color); - 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); - - res.set_input("transmission", transmission); - res.set_input("transmission_color", base_color); - 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); - res.set_input("subsurface_anisotropy", anisotropic); - - res.set_input("sheen", sheen); - res.set_input("sheen_color", base_color); - res.set_input("sheen_roughness", roughness); - - res.set_input("coat", clearcoat); - res.set_input("coat_color", base_color); - 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); - } - - res.set_input("emission", emission_strength); - res.set_input("emission_color", emission); - - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc deleted file mode 100644 index 2818cb52c29..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_refraction.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFRefractionNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc deleted file mode 100644 index 7672813a63f..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFSheenNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc deleted file mode 100644 index 0c8fffa5780..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFToonNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc deleted file mode 100644 index 82779b4203b..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_translucent.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFTranslucentNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc b/source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc deleted file mode 100644 index c9310de8ac3..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/bsdf_transparent.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem BSDFTransparentNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/clamp.cc b/source/blender/nodes/shader/materialx/nodes/clamp.cc deleted file mode 100644 index 035a6dd9834..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/clamp.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem ClampNodeParser::compute() -{ - auto type = node_->custom1; - NodeItem value = get_input_value("Value", NodeItem::Type::Float); - NodeItem min = get_input_value("Min", NodeItem::Type::Float); - NodeItem max = get_input_value("Max", NodeItem::Type::Float); - - NodeItem res = empty(); - if (type == NODE_CLAMP_RANGE) { - res = min.if_else( - NodeItem::CompareOp::Less, max, value.clamp(min, max), value.clamp(max, min)); - } - else { - res = value.clamp(min, max); - } - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/color_ramp.cc b/source/blender/nodes/shader/materialx/nodes/color_ramp.cc deleted file mode 100644 index b95f272c21c..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/color_ramp.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem ColorRampNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/curves.cc b/source/blender/nodes/shader/materialx/nodes/curves.cc deleted file mode 100644 index e8ff16f6e80..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/curves.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem CurvesRGBNodeParser::compute() -{ - /* TODO: implement */ - return get_input_value("Color", NodeItem::Type::Color4); -} - -NodeItem CurvesFloatNodeParser::compute() -{ - /* TODO: implement */ - return get_input_value("Value", NodeItem::Type::Float); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/emission.cc b/source/blender/nodes/shader/materialx/nodes/emission.cc deleted file mode 100644 index f737c328bc8..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/emission.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem EmissionNodeParser::compute() -{ - if (shader_type_ != NodeItem::Type::EDF) { - return empty(); - } - - NodeItem color = get_input_value("Color", NodeItem::Type::Color3); - NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); - - NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF); - res.set_input("color", color * strength); - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/gamma.cc b/source/blender/nodes/shader/materialx/nodes/gamma.cc deleted file mode 100644 index ef4b88e0594..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/gamma.cc +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem GammaNodeParser::compute() -{ - NodeItem color = get_input_value("Color", NodeItem::Type::Color4); - NodeItem gamma = get_input_value("Gamma", NodeItem::Type::Float); - - return color ^ gamma; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/huesatval.cc b/source/blender/nodes/shader/materialx/nodes/huesatval.cc deleted file mode 100644 index 3f66e2f5ca0..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/huesatval.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* 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::Type::Float); - NodeItem saturation = get_input_value("Saturation", NodeItem::Type::Float); - NodeItem value = get_input_value("Value", NodeItem::Type::Float); - NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); - NodeItem color = get_input_value("Color", NodeItem::Type::Color3); - - /* Modifier to follow Cycles result */ - hue = hue - val(0.5f); - - NodeItem combine = create_node("combine3", NodeItem::Type::Vector3); - combine.set_input("in1", hue); - combine.set_input("in2", saturation); - combine.set_input("in3", value); - - NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3); - res.set_input("in", color); - res.set_input("amount", combine); - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/invert.cc b/source/blender/nodes/shader/materialx/nodes/invert.cc deleted file mode 100644 index 47ef4857899..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/invert.cc +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem InvertNodeParser::compute() -{ - NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); - NodeItem color = get_input_value("Color", NodeItem::Type::Color3); - return fac.blend(color, fac.val(1.0f) - color); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/light_falloff.cc b/source/blender/nodes/shader/materialx/nodes/light_falloff.cc deleted file mode 100644 index 81186747540..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/light_falloff.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem LightFalloffNodeParser::compute() -{ - NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); - NodeItem smooth = get_input_value("Smooth", NodeItem::Type::Float); - - /* This node isn't supported by MaterialX. This formula was given from OSL shader code in Cycles - * node_light_falloff.osl. Considered ray_length=1.0f. */ - strength = strength * val(1.0f) / (smooth + val(1.0f)); - - return strength; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/light_path.cc b/source/blender/nodes/shader/materialx/nodes/light_path.cc deleted file mode 100644 index 0c58f89d6bf..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/light_path.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem LightPathNodeParser::compute() -{ - /* This node isn't supported by MaterialX. Only default values returned. */ - if (STREQ(socket_out_->name, "Is Camera Ray")) { - return val(1.0f); - } - if (STREQ(socket_out_->name, "Ray Length")) { - return val(1.0f); - } - return val(0.0f); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/map_range.cc b/source/blender/nodes/shader/materialx/nodes/map_range.cc deleted file mode 100644 index a0ac1a6b223..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/map_range.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem MapRangeNodeParser::compute() -{ - /* Interpolation isn't supported by MaterialX. */ - const NodeMapRange *map_range = static_cast(node_->storage); - - NodeItem::Type type; - NodeItem value = empty(); - NodeItem from_min = empty(); - NodeItem from_max = empty(); - NodeItem to_min = empty(); - NodeItem to_max = empty(); - switch (map_range->data_type) { - case CD_PROP_FLOAT: - type = NodeItem::Type::Float; - value = get_input_value("Value", type); - from_min = get_input_value(1, type); - from_max = get_input_value(2, type); - to_min = get_input_value(3, type); - to_max = get_input_value(4, type); - break; - case CD_PROP_FLOAT3: - type = NodeItem::Type::Vector3; - value = get_input_value("Vector", type); - from_min = get_input_value(7, type); - from_max = get_input_value(8, type); - to_min = get_input_value(9, type); - to_max = get_input_value(10, type); - break; - default: - BLI_assert_unreachable(); - } - - NodeItem res = create_node("range", type); - res.set_input("in", value); - res.set_input("inlow", from_min); - res.set_input("inhigh", from_max); - res.set_input("outlow", to_min); - res.set_input("outhigh", to_max); - res.set_input("doclamp", val(bool(map_range->clamp))); - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc deleted file mode 100644 index 9af8f665769..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* 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 MathNodeParser::compute() -{ - /* TODO: finish some math operations */ - NodeMathOperation op = NodeMathOperation(node_->custom1); - NodeItem res = empty(); - - /* Single operand operations */ - NodeItem x = get_input_value(0, NodeItem::Type::Float); - /* TODO: Seems we have to use average if Vector or Color are added */ - - switch (op) { - case NODE_MATH_SINE: - res = x.sin(); - break; - case NODE_MATH_COSINE: - res = x.cos(); - break; - case NODE_MATH_TANGENT: - res = x.tan(); - break; - case NODE_MATH_ARCSINE: - res = x.asin(); - break; - case NODE_MATH_ARCCOSINE: - res = x.acos(); - break; - case NODE_MATH_ARCTANGENT: - res = x.atan(); - break; - case NODE_MATH_ROUND: - res = (x + val(0.5f)).floor(); - break; - case NODE_MATH_ABSOLUTE: - res = x.abs(); - break; - case NODE_MATH_FLOOR: - res = x.floor(); - break; - case NODE_MATH_CEIL: - res = x.ceil(); - break; - case NODE_MATH_FRACTION: - res = x % val(1.0f); - break; - case NODE_MATH_SQRT: - res = x.sqrt(); - break; - case NODE_MATH_INV_SQRT: - res = val(1.0f) / x.sqrt(); - break; - case NODE_MATH_SIGN: - res = x.sign(); - break; - case NODE_MATH_EXPONENT: - res = x.exp(); - break; - case NODE_MATH_RADIANS: - res = x * val(float(M_PI) / 180.0f); - break; - case NODE_MATH_DEGREES: - res = x * val(180.0f * float(M_1_PI)); - break; - case NODE_MATH_SINH: - res = x.sinh(); - break; - case NODE_MATH_COSH: - res = x.cosh(); - break; - case NODE_MATH_TANH: - res = x.tanh(); - break; - case NODE_MATH_TRUNC: - res = x.sign() * x.abs().floor(); - break; - - default: { - /* 2-operand operations */ - NodeItem y = get_input_value(1, NodeItem::Type::Float); - switch (op) { - case NODE_MATH_ADD: - res = x + y; - break; - case NODE_MATH_SUBTRACT: - res = x - y; - break; - case NODE_MATH_MULTIPLY: - res = x * y; - break; - case NODE_MATH_DIVIDE: - res = x / y; - break; - case NODE_MATH_POWER: - res = x ^ y; - break; - case NODE_MATH_LOGARITHM: - res = x.ln() / y.ln(); - break; - case NODE_MATH_MINIMUM: - res = x.min(y); - break; - case NODE_MATH_MAXIMUM: - res = x.max(y); - break; - case NODE_MATH_LESS_THAN: - res = x.if_else(NodeItem::CompareOp::Less, y, val(1.0f), val(0.0f)); - break; - case NODE_MATH_GREATER_THAN: - res = x.if_else(NodeItem::CompareOp::Greater, y, val(1.0f), val(0.0f)); - break; - case NODE_MATH_MODULO: - res = x % y; - break; - case NODE_MATH_ARCTAN2: - res = x.atan2(y); - break; - case NODE_MATH_SNAP: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); - break; - case NODE_MATH_PINGPONG: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); - break; - case NODE_MATH_FLOORED_MODULO: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); - break; - - default: { - /* 3-operand operations */ - NodeItem z = get_input_value(2, NodeItem::Type::Float); - switch (op) { - case NODE_MATH_WRAP: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); - break; - case NODE_MATH_COMPARE: - res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), val(1.0f), val(0.0f)); - break; - case NODE_MATH_MULTIPLY_ADD: - res = x * y + z; - break; - case NODE_MATH_SMOOTH_MIN: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); - break; - case NODE_MATH_SMOOTH_MAX: - CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); - break; - - default: - BLI_assert_unreachable(); - } - } - } - } - } - - bool clamp_output = node_->custom2 != 0; - if (clamp_output && res) { - res = res.clamp(); - } - - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc b/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc deleted file mode 100644 index c06cf322a0f..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/mix_rgb.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem MixRGBNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/mix_shader.cc b/source/blender/nodes/shader/materialx/nodes/mix_shader.cc deleted file mode 100644 index 40a1575d24c..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/mix_shader.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem MixShaderNodeParser::compute() -{ - NodeItem res = empty(); - switch (shader_type_) { - case NodeItem::Type::BSDF: - case NodeItem::Type::EDF: { - NodeItem fac = get_input_value(0, NodeItem::Type::Float); - NodeItem shader1 = get_input_shader(1, shader_type_); - NodeItem shader2 = get_input_shader(2, shader_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", shader_type_); - res.set_input("fg", shader1); - res.set_input("bg", shader2); - res.set_input("mix", fac); - } - break; - } - case NodeItem::Type::SurfaceShader: { - res = get_input_shader(1, NodeItem::Type::SurfaceShader); - if (!res) { - res = get_input_shader(2, NodeItem::Type::SurfaceShader); - } - break; - } - default: - BLI_assert_unreachable(); - } - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc deleted file mode 100644 index f68ec48949d..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ /dev/null @@ -1,318 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" -#include "../material.h" - -#include "BKE_node_runtime.hh" - -namespace blender::nodes::materialx { - -static const std::string TEXCOORD_NODE_NAME = "node_texcoord"; - -NodeParser::NodeParser(MaterialX::GraphElement *graph, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node, - const bNodeSocket *socket_out) - : graph_(graph), - depsgraph_(depsgraph), - material_(material), - node_(node), - socket_out_(socket_out) -{ -} - -NodeItem NodeParser::compute_full() -{ - CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type); - NodeItem res = compute(); - if (res.node) { - res.node->setName(node_name()); - } - return res; -} - -std::string NodeParser::node_name() -{ - return MaterialX::createValidName(node_->output_sockets().size() <= 1 ? - std::string(node_->name) : - std::string(node_->name) + "_" + socket_out_->name); -} - -NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type) -{ - return empty().create_node(category, type); -} - -NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) -{ - return get_input_default(node_->input_by_identifier(name), to_type); -} - -NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type) -{ - return get_input_default(node_->input_socket(index), to_type); -} - -NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type) -{ - return get_input_link(node_->input_by_identifier(name), to_type); -} - -NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type) -{ - return get_input_link(node_->input_socket(index), to_type); -} - -NodeItem NodeParser::get_input_value(const std::string &name, NodeItem::Type to_type) -{ - return get_input_value(node_->input_by_identifier(name), to_type); -} - -NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type) -{ - return get_input_value(node_->input_socket(index), to_type); -} - -NodeItem NodeParser::empty() const -{ - return NodeItem(graph_); -} - -NodeItem NodeParser::texcoord_node() -{ - NodeItem res = empty(); - res.node = graph_->getNode(TEXCOORD_NODE_NAME); - if (!res.node) { - res = create_node("texcoord", NodeItem::Type::Vector2); - res.node->setName(TEXCOORD_NODE_NAME); - } - return res; -} - -NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type) -{ - NodeItem res = empty(); - switch (socket.type) { - case SOCK_FLOAT: { - float v = socket.default_value_typed()->value; - res.value = MaterialX::Value::createValue(v); - break; - } - case SOCK_VECTOR: { - const float *v = socket.default_value_typed()->value; - res.value = MaterialX::Value::createValue( - MaterialX::Vector3(v[0], v[1], v[2])); - break; - } - case SOCK_RGBA: { - const float *v = socket.default_value_typed()->value; - res.value = MaterialX::Value::createValue( - MaterialX::Color4(v[0], v[1], v[2], v[3])); - break; - } - default: { - CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type); - } - } - return res.convert(to_type); -} - -NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to_type) -{ - NodeItem res = empty(); - - const bNodeLink *link = socket.link; - if (!(link && link->is_used())) { - return res; - } - - const bNode *from_node = link->fromnode; - - /* Passing NODE_REROUTE nodes */ - while (from_node->type == NODE_REROUTE) { - link = from_node->input_socket(0).link; - if (!(link && link->is_used())) { - return res; - } - from_node = link->fromnode; - } - - /* Creating required NodeParser object */ - std::unique_ptr parser; - -#define CASE_NODE_TYPE(type, T) \ - case type: \ - parser = std::make_unique(graph_, depsgraph_, material_, from_node, link->fromsock); \ - break; - - switch (from_node->typeinfo->type) { - CASE_NODE_TYPE(SH_NODE_BLACKBODY, BlackbodyNodeParser) - CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser) - CASE_NODE_TYPE(SH_NODE_CLAMP, ClampNodeParser) - CASE_NODE_TYPE(SH_NODE_VALTORGB, ColorRampNodeParser) - CASE_NODE_TYPE(SH_NODE_CURVE_FLOAT, CurvesFloatNodeParser) - CASE_NODE_TYPE(SH_NODE_CURVE_RGB, CurvesRGBNodeParser) - CASE_NODE_TYPE(SH_NODE_GAMMA, GammaNodeParser) - 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_LIGHT_FALLOFF, LightFalloffNodeParser) - CASE_NODE_TYPE(SH_NODE_LIGHT_PATH, LightPathNodeParser) - CASE_NODE_TYPE(SH_NODE_MAP_RANGE, MapRangeNodeParser) - 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_RGBTOBW, RGBToBWNodeParser) - 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) - CASE_NODE_TYPE(SH_NODE_WAVELENGTH, WavelengthNodeParser) - - default: - CLOG_WARN(LOG_MATERIALX_SHADER, - "Unsupported node: %s [%d]", - from_node->name, - from_node->typeinfo->type); - } - if (!parser) { - return res; - } - - /* Checking if node was already computed */ - res.node = graph_->getNode(parser->node_name()); - if (res.node) { - return res; - } - - /* Computing */ - res = parser->compute_full(); - return res.convert(to_type); -} - -NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type to_type) -{ - NodeItem res = get_input_link(socket, to_type); - if (!res) { - res = get_input_default(socket, to_type); - } - return res; -} - -ShaderNodeParser::ShaderNodeParser(MaterialX::GraphElement *graph, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node, - const bNodeSocket *socket_out, - NodeItem::Type shader_type) - : NodeParser(graph, depsgraph, material, node, socket_out), shader_type_(shader_type) -{ -} - -NodeItem ShaderNodeParser::compute_full() -{ - CLOG_INFO(LOG_MATERIALX_SHADER, - 1, - "%s [%d] - %s", - node_->name, - node_->typeinfo->type, - NodeItem::type(shader_type_).c_str()); - NodeItem res = compute(); - if (res.node) { - res.node->setName(node_name()); - } - return res; -} - -std::string ShaderNodeParser::node_name() -{ - std::string name = NodeParser::node_name(); - if (shader_type_ != NodeItem::Type::SurfaceShader) { - name += "_" + NodeItem::type(shader_type_); - } - return name; -} - -NodeItem ShaderNodeParser::get_input_shader(const std::string &name, NodeItem::Type shader_type) -{ - return get_input_shader(node_->input_by_identifier(name), shader_type); -} - -NodeItem ShaderNodeParser::get_input_shader(int index, NodeItem::Type shader_type) -{ - return get_input_shader(node_->input_socket(index), shader_type); -} - -NodeItem ShaderNodeParser::get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type) -{ - NodeItem res = empty(); - - const bNodeLink *link = socket.link; - if (!(link && link->is_used())) { - return res; - } - - const bNode *from_node = link->fromnode; - - /* Passing NODE_REROUTE nodes */ - while (from_node->type == NODE_REROUTE) { - link = from_node->input_socket(0).link; - if (!(link && link->is_used())) { - return res; - } - from_node = link->fromnode; - } - - /* Creating required ShaderNodeParser object */ - std::unique_ptr parser; - -#define CASE_SHADER_NODE_TYPE(type, T) \ - case type: \ - parser = std::make_unique( \ - graph_, depsgraph_, material_, from_node, link->fromsock, shader_type); \ - break; - - switch (from_node->typeinfo->type) { - CASE_SHADER_NODE_TYPE(SH_NODE_ADD_SHADER, AddShaderNodeParser) - CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_DIFFUSE, BSDFDiffuseNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLASS, BSDFGlassNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLOSSY, BSDFGlossyNodeParser) - CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_REFRACTION, BSDFRefractionNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_SHEEN, BSDFSheenNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TOON, BSDFToonNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSLUCENT, BSDFTranslucentNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSPARENT, BSDFTransparentNodeParser) - CASE_SHADER_NODE_TYPE(SH_NODE_EMISSION, EmissionNodeParser) - CASE_SHADER_NODE_TYPE(SH_NODE_MIX_SHADER, MixShaderNodeParser) - // CASE_SHADER_NODE_TYPE(SH_NODE_SUBSURFACE_SCATTERING, SubsurfaceScatteringNodeParser) - - default: - CLOG_WARN(LOG_MATERIALX_SHADER, - "Unsupported node: %s [%d]", - from_node->name, - from_node->typeinfo->type); - } - if (!parser) { - return res; - } - - /* Checking if node was already computed */ - res.node = graph_->getNode(parser->node_name()); - if (res.node) { - return res; - } - - /* Computing */ - res = parser->compute_full(); - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h deleted file mode 100644 index a327352629f..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ /dev/null @@ -1,135 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include "node_item.h" - -#include "DEG_depsgraph.h" -#include "DNA_material_types.h" -#include "DNA_node_types.h" - -namespace blender::nodes::materialx { - -class NodeParser { - protected: - MaterialX::GraphElement *graph_; - const Depsgraph *depsgraph_; - const Material *material_; - const bNode *node_; - const bNodeSocket *socket_out_; - - public: - NodeParser(MaterialX::GraphElement *graph, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node, - const bNodeSocket *socket_out); - virtual ~NodeParser() = default; - - virtual NodeItem compute() = 0; - - protected: - virtual NodeItem compute_full(); - virtual std::string node_name(); - NodeItem create_node(const std::string &category, NodeItem::Type type); - NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); - NodeItem get_input_default(int index, NodeItem::Type to_type); - NodeItem get_input_link(const std::string &name, NodeItem::Type to_type); - NodeItem get_input_link(int index, NodeItem::Type to_type); - NodeItem get_input_value(const std::string &name, NodeItem::Type to_type); - NodeItem get_input_value(int index, NodeItem::Type to_type); - NodeItem empty() const; - template NodeItem val(const T &data) const; - NodeItem texcoord_node(); - - private: - NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); - NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type); - NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type); -}; - -class ShaderNodeParser : public NodeParser { - protected: - NodeItem::Type shader_type_; - - public: - ShaderNodeParser(MaterialX::GraphElement *graph, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node, - const bNodeSocket *socket_out, - NodeItem::Type shader_type); - - protected: - NodeItem compute_full() override; - std::string node_name() override; - NodeItem get_input_shader(const std::string &name, NodeItem::Type shader_type); - NodeItem get_input_shader(int index, NodeItem::Type shader_type); - - private: - NodeItem get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type); -}; - -template NodeItem NodeParser::val(const T &data) const -{ - return empty().val(data); -} - -#define DECLARE_NODE_PARSER(T) \ - class T : public NodeParser { \ - public: \ - using NodeParser::NodeParser; \ - NodeItem compute() override; \ - }; - -#define DECLARE_SHADER_NODE_PARSER(T) \ - class T : public ShaderNodeParser { \ - public: \ - using ShaderNodeParser::ShaderNodeParser; \ - NodeItem compute() override; \ - }; - -DECLARE_NODE_PARSER(BlackbodyNodeParser) -DECLARE_NODE_PARSER(BrightContrastNodeParser) -DECLARE_NODE_PARSER(ClampNodeParser) -DECLARE_NODE_PARSER(ColorRampNodeParser) -DECLARE_NODE_PARSER(CurvesFloatNodeParser) -DECLARE_NODE_PARSER(CurvesRGBNodeParser) -DECLARE_NODE_PARSER(CombineColorNodeParser) -DECLARE_NODE_PARSER(CombineXYZNodeParser) -DECLARE_NODE_PARSER(GammaNodeParser) -DECLARE_NODE_PARSER(HueSatValNodeParser) -DECLARE_NODE_PARSER(InvertNodeParser) -DECLARE_NODE_PARSER(LightFalloffNodeParser) -DECLARE_NODE_PARSER(LightPathNodeParser) -DECLARE_NODE_PARSER(MapRangeNodeParser) -DECLARE_NODE_PARSER(MathNodeParser) -DECLARE_NODE_PARSER(MixRGBNodeParser) -DECLARE_NODE_PARSER(NormalMapNodeParser) -DECLARE_NODE_PARSER(RGBToBWNodeParser) -DECLARE_NODE_PARSER(SeparateColorNodeParser) -DECLARE_NODE_PARSER(SeparateXYZNodeParser) -DECLARE_NODE_PARSER(TexCheckerNodeParser) -DECLARE_NODE_PARSER(TexEnvironmentNodeParser) -DECLARE_NODE_PARSER(TexImageNodeParser) -DECLARE_NODE_PARSER(TexNoiseNodeParser) -DECLARE_NODE_PARSER(VectorMathNodeParser) -DECLARE_NODE_PARSER(WavelengthNodeParser) - -DECLARE_SHADER_NODE_PARSER(AddShaderNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFDiffuseNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFGlassNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFGlossyNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFPrincipledNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFRefractionNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFSheenNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFToonNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFTranslucentNodeParser) -DECLARE_SHADER_NODE_PARSER(BSDFTransparentNodeParser) -DECLARE_SHADER_NODE_PARSER(EmissionNodeParser) -DECLARE_SHADER_NODE_PARSER(MixShaderNodeParser) -DECLARE_SHADER_NODE_PARSER(SubsurfaceScatteringNodeParser) - -} // 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 deleted file mode 100644 index 1a51911a22f..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/normal_map.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* 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::Type::Color3); - NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); - - NodeItem res = create_node("normalmap", NodeItem::Type::Vector3); - res.set_input("in", color); - res.set_input("scale", strength); - - switch (normal_map_node->space) { - case SHD_SPACE_TANGENT: - res.set_input("space", val(std::string("tangent"))); - break; - case SHD_SPACE_OBJECT: - res.set_input("space", val(std::string("tangent"))); - break; - default: - res.set_input("space", val(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/output_material.cc b/source/blender/nodes/shader/materialx/nodes/output_material.cc deleted file mode 100644 index 4de4991d1dd..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/output_material.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "output_material.h" - -namespace blender::nodes::materialx { -OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *graph, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node) - : ShaderNodeParser(graph, depsgraph, material, node, nullptr, NodeItem::Type::Material) -{ -} - -NodeItem OutputMaterialNodeParser::compute() -{ - NodeItem surface = empty(); - if (node_) { - NodeItem bsdf = get_input_shader("Surface", NodeItem::Type::BSDF); - NodeItem edf = get_input_shader("Surface", NodeItem::Type::EDF); - if (bsdf || edf) { - surface = create_node("surface", NodeItem::Type::SurfaceShader); - if (bsdf) { - surface.set_input("bsdf", bsdf); - } - if (edf) { - surface.set_input("edf", edf); - } - } - else { - surface = get_input_shader("Surface", NodeItem::Type::SurfaceShader); - } - } - else { - surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); - surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f))); - } - NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); - res.set_input("surfaceshader", surface); - return res; -} - -NodeItem OutputMaterialNodeParser::compute_default() -{ - NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); - surface.set_input("base_color", - val(MaterialX::Color3(material_->r, material_->g, material_->b))); - surface.set_input("diffuse_roughness", val(material_->roughness)); - if (material_->metallic > 0.0f) { - surface.set_input("metalness", val(material_->metallic)); - } - if (material_->spec) { - surface.set_input("specular", val(material_->spec)); - surface.set_input("specular_color", val(material_->spec)); - surface.set_input("specular_roughness", val(material_->roughness)); - } - - NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); - res.node->setName("Material_Default"); - res.set_input("surfaceshader", surface); - return res; -} - -std::string OutputMaterialNodeParser::node_name() -{ - return NodeParser::node_name(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/output_material.h b/source/blender/nodes/shader/materialx/nodes/output_material.h deleted file mode 100644 index 9f75d8761f8..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/output_material.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -class OutputMaterialNodeParser : public ShaderNodeParser { - public: - OutputMaterialNodeParser(MaterialX::GraphElement *graph, - const Depsgraph *depsgraph, - const Material *material, - const bNode *node); - NodeItem compute() override; - - using ShaderNodeParser::compute_full; - NodeItem compute_default(); - - protected: - std::string node_name() override; -}; - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc b/source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc deleted file mode 100644 index 26ed2469432..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/rgb_to_bw.cc +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem RGBToBWNodeParser::compute() -{ - NodeItem color = get_input_value("Color", NodeItem::Type::Color4); - - NodeItem res = create_node("luminance", NodeItem::Type::Color4); - res.set_input("in", color); - 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 deleted file mode 100644 index e3398d8a4a4..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/sepcomb_color.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* 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::Type::Color3); - - NodeItem convert = empty(); - - switch (mode) { - case NODE_COMBSEP_COLOR_RGB: - break; - case NODE_COMBSEP_COLOR_HSV: - convert = create_node("rgbtohsv", NodeItem::Type::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", NodeItem::Type::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::Type::Float); - NodeItem green = get_input_value("Green", NodeItem::Type::Float); - NodeItem blue = get_input_value("Blue", NodeItem::Type::Float); - - NodeItem convert = empty(); - NodeItem combine = create_node("combine3", NodeItem::Type::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", NodeItem::Type::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", NodeItem::Type::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 deleted file mode 100644 index e228edf708a..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/sepcomb_xyz.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* 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", NodeItem::Type::Vector3); - 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::Type::Float); - NodeItem y = get_input_value("Y", NodeItem::Type::Float); - NodeItem z = get_input_value("Z", NodeItem::Type::Float); - NodeItem res = create_node("combine3", NodeItem::Type::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/subsurface_scattering.cc b/source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc deleted file mode 100644 index 7efddb150a6..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/subsurface_scattering.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem SubsurfaceScatteringNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc deleted file mode 100644 index 1d58e0e14a8..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem TexCheckerNodeParser::compute() -{ - NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); - if (!vector) { - vector = texcoord_node(); - } - NodeItem value1 = val(1.0f); - NodeItem value2 = val(0.0f); - if (STREQ(socket_out_->name, "Color")) { - value1 = get_input_value("Color1", NodeItem::Type::Color4); - value2 = get_input_value("Color2", NodeItem::Type::Color4); - } - NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); - - vector = (vector * scale) % val(2.0f); - return (vector.extract(0).floor() + vector.extract(1).floor()) - .if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc deleted file mode 100644 index 65b5c451559..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -#include "hydra/image.h" - -#include "DEG_depsgraph_query.h" - -namespace blender::nodes::materialx { - -NodeItem TexEnvironmentNodeParser::compute() -{ - NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); - - Image *image = (Image *)node_->id; - if (!image) { - return res; - } - - NodeTexEnvironment *tex_env = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); - - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains - * pretty general code, so could be moved from bf_usd project. */ - std::string image_path = io::hydra::cache_or_get_image_file( - bmain, scene, image, &tex_env->iuser); - - NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); - if (!vector) { - vector = texcoord_node(); - } - /* TODO: texcoords should be translated to spherical coordinates */ - - std::string filtertype; - switch (tex_env->interpolation) { - case SHD_INTERP_LINEAR: - filtertype = "linear"; - break; - case SHD_INTERP_CLOSEST: - filtertype = "closest"; - break; - case SHD_INTERP_CUBIC: - case SHD_INTERP_SMART: - filtertype = "cubic"; - break; - default: - BLI_assert_unreachable(); - } - - res = create_node("image", NodeItem::Type::Color4); - res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", vector); - res.set_input("filtertype", val(filtertype)); - - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc deleted file mode 100644 index 75c30a0a045..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -#include "hydra/image.h" - -#include "DEG_depsgraph_query.h" - -namespace blender::nodes::materialx { - -NodeItem TexImageNodeParser::compute() -{ - NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); - - Image *image = (Image *)node_->id; - if (image) { - NodeTexImage *tex_image = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); - - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains - * pretty general code, so could be moved from bf_usd project. */ - std::string image_path = io::hydra::cache_or_get_image_file( - bmain, scene, image, &tex_image->iuser); - - NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); - if (!vector) { - vector = texcoord_node(); - } - /* TODO: add math to vector depending of tex_image->projection */ - - std::string filtertype; - switch (tex_image->interpolation) { - case SHD_INTERP_LINEAR: - filtertype = "linear"; - break; - case SHD_INTERP_CLOSEST: - filtertype = "closest"; - break; - case SHD_INTERP_CUBIC: - case SHD_INTERP_SMART: - filtertype = "cubic"; - break; - default: - BLI_assert_unreachable(); - } - std::string addressmode; - switch (tex_image->extension) { - case SHD_IMAGE_EXTENSION_REPEAT: - addressmode = "periodic"; - break; - case SHD_IMAGE_EXTENSION_EXTEND: - addressmode = "clamp"; - break; - case SHD_IMAGE_EXTENSION_CLIP: - addressmode = "constant"; - break; - case SHD_IMAGE_EXTENSION_MIRROR: - addressmode = "mirror"; - break; - default: - BLI_assert_unreachable(); - } - - res = create_node("image", NodeItem::Type::Color4); - res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", vector); - res.set_input("filtertype", val(filtertype)); - res.set_input("uaddressmode", val(addressmode)); - res.set_input("vaddressmode", val(addressmode)); - } - - if (STREQ(socket_out_->name, "Alpha")) { - res = res.extract(3); - } - return res; -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc b/source/blender/nodes/shader/materialx/nodes/tex_noise.cc deleted file mode 100644 index ce6511b55d5..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/tex_noise.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem TexNoiseNodeParser::compute() -{ - NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); - NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); - NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); - - if (detail.value && detail.type() == NodeItem::Type::Float) { - detail = val(int(detail.value->asA())); - } - - NodeItem position = create_node("position", NodeItem::Type::Vector3); - position = position * scale; - - NodeItem res = create_node("fractal3d", NodeItem::Type::Color3); - res.set_input("position", position); - res.set_input("octaves", detail); - res.set_input("lacunarity", lacunarity); - 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 deleted file mode 100644 index 51a6d6599f7..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/vector_math.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* 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, NodeItem::Type::Any); - 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 % val(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, NodeItem::Type::Any); - 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, NodeItem::Type::Any); - 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 diff --git a/source/blender/nodes/shader/materialx/nodes/wavelength.cc b/source/blender/nodes/shader/materialx/nodes/wavelength.cc deleted file mode 100644 index 892504e1727..00000000000 --- a/source/blender/nodes/shader/materialx/nodes/wavelength.cc +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "node_parser.h" - -namespace blender::nodes::materialx { - -NodeItem WavelengthNodeParser::compute() -{ - /* TODO: implement */ - return empty(); -} - -} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index c41023cb804..a19b849136e 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -22,6 +22,8 @@ #include "node_shader_register.hh" +#include "materialx/node_parser.h" + struct bContext; typedef struct bContext bContext; struct bNodeExecContext; diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc index 5cd119ee810..ae520a0131e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc @@ -22,6 +22,41 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_add_shader", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem res = empty(); + switch (to_type_) { + 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; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_add_shader_cc /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc index f1f6df66abf..a84b0d3414e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc +++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc @@ -31,6 +31,20 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer)); } +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: This node doesn't have an implementation in MaterialX 1.38.6. + * It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8. + * + * NodeItem temperature = get_input_value("Temperature", NodeItem::Type::Float); + + * NodeItem res = create_node("blackbody", NodeItem::Type::Color3); + * res.set_input("temperature", temperature); + * return res; */ + return empty(); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_blackbody_cc /* node type definition */ @@ -44,6 +58,7 @@ void register_node_type_sh_blackbody() ntype.declare = file_ns::node_declare; blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_blackbody; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.cc b/source/blender/nodes/shader/nodes/node_shader_brightness.cc index eff05fdb125..1172ebf1b92 100644 --- a/source/blender/nodes/shader/nodes/node_shader_brightness.cc +++ b/source/blender/nodes/shader/nodes/node_shader_brightness.cc @@ -23,6 +23,17 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat, return GPU_stack_link(mat, node, "brightness_contrast", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem bright = get_input_value("Bright", NodeItem::Type::Float); + NodeItem contrast = get_input_value("Contrast", NodeItem::Type::Float); + + /* This formula was given from OSL shader code in Cycles. */ + return (bright + color * (contrast + val(1.0f)) - contrast * val(0.5f)).max(val(0.0f)); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_brightness_cc void register_node_type_sh_brightcontrast() @@ -34,6 +45,7 @@ void register_node_type_sh_brightcontrast() sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Brightness/Contrast", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_brightcontrast; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index 5aeb70dfa32..3e05d4fd202 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -34,6 +34,26 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF); + res.set_input("color", color); + res.set_input("roughness", roughness); + if (normal) { + res.set_input("normal", normal); + } + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_diffuse_cc /* node type definition */ @@ -48,6 +68,7 @@ void register_node_type_sh_bsdf_diffuse() ntype.add_ui_poll = object_shader_nodes_poll; blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_diffuse; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index d9028ef974d..55d55a8ca37 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -253,6 +253,99 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node) } } +NODE_SHADER_MATERIALX_BEGIN +{ + if (to_type_ != NodeItem::Type::SurfaceShader) { + /* TODO: implement for BSDF and EDF */ + return empty(); + } + + NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3); + + NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float); + NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3); + NodeItem subsurface_color = get_input_value("Subsurface Color", NodeItem::Type::Color3); + + NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float); + NodeItem specular = get_input_value("Specular", NodeItem::Type::Float); + // NodeItem specular_tint = get_input_value("Specular Tint"); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); + + /* TODO: use Specular Tint input */ + NodeItem anisotropic = get_input_value("Anisotropic", NodeItem::Type::Float); + NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation", NodeItem::Type::Float); + // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) + + NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float); + // sheen_tint = get_input_value("Sheen Tint"); + + NodeItem clearcoat = get_input_value("Clearcoat", NodeItem::Type::Float); + NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness", NodeItem::Type::Float); + + NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); + + NodeItem transmission = get_input_value("Transmission", NodeItem::Type::Float); + + NodeItem emission = get_input_value("Emission", NodeItem::Type::Color3); + NodeItem emission_strength = get_input_value("Emission Strength", NodeItem::Type::Float); + + NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float); + // transparency = 1.0 - alpha + + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3); + NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); + + /* Creating standard_surface */ + NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader); + res.set_input("base", val(1.0f)); + res.set_input("base_color", base_color); + res.set_input("diffuse_roughness", roughness); + if (normal) { + res.set_input("normal", normal); + } + if (tangent) { + res.set_input("tangent", tangent); + } + res.set_input("metalness", metallic); + + res.set_input("specular", specular); + res.set_input("specular_color", base_color); + 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); + + res.set_input("transmission", transmission); + res.set_input("transmission_color", base_color); + 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); + res.set_input("subsurface_anisotropy", anisotropic); + + res.set_input("sheen", sheen); + res.set_input("sheen_color", base_color); + res.set_input("sheen_roughness", roughness); + + res.set_input("coat", clearcoat); + res.set_input("coat_color", base_color); + 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); + } + + res.set_input("emission", emission_strength); + res.set_input("emission_color", emission); + + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_principled_cc /* node type definition */ @@ -270,6 +363,7 @@ void register_node_type_sh_bsdf_principled() ntype.initfunc = file_ns::node_shader_init_principled; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_principled; ntype.updatefunc = file_ns::node_shader_update_principled; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index 6f56b6b7e3a..576b8eebee4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -70,6 +70,25 @@ static void sh_node_clamp_build_multi_function(NodeMultiFunctionBuilder &builder } } +NODE_SHADER_MATERIALX_BEGIN +{ + auto type = node_->custom1; + NodeItem value = get_input_value("Value", NodeItem::Type::Float); + NodeItem min = get_input_value("Min", NodeItem::Type::Float); + NodeItem max = get_input_value("Max", NodeItem::Type::Float); + + NodeItem res = empty(); + if (type == NODE_CLAMP_RANGE) { + res = min.if_else( + NodeItem::CompareOp::Less, max, value.clamp(min, max), value.clamp(max, min)); + } + else { + res = value.clamp(min, max); + } + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_clamp_cc void register_node_type_sh_clamp() @@ -84,6 +103,7 @@ void register_node_type_sh_clamp() ntype.initfunc = file_ns::node_shader_init_clamp; ntype.gpu_fn = file_ns::gpu_shader_clamp; ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc index 09aa313833a..dbac50fa0e0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -136,6 +136,13 @@ static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilde builder.construct_and_set_matching_fn(*color_band); } +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: Implement */ + return empty(); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_color_ramp_cc void register_node_type_sh_valtorgb() @@ -151,6 +158,7 @@ void register_node_type_sh_valtorgb() node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::gpu_shader_valtorgb; ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index 6c9cd10db29..046d16d84b1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -16,7 +16,7 @@ #include "node_util.hh" -namespace blender::nodes::node_shader_curves_cc { +namespace blender::nodes::node_shader_curves_cc::vec { static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b) { @@ -109,11 +109,18 @@ static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &bui builder.construct_and_set_matching_fn(*cumap); } -} // namespace blender::nodes::node_shader_curves_cc +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: implement */ + return get_input_value("Value", NodeItem::Type::Vector3); +} +NODE_SHADER_MATERIALX_END + +} // namespace blender::nodes::node_shader_curves_cc::vec void register_node_type_sh_curve_vec() { - namespace file_ns = blender::nodes::node_shader_curves_cc; + namespace file_ns = blender::nodes::node_shader_curves_cc::vec; static bNodeType ntype; @@ -124,13 +131,14 @@ void register_node_type_sh_curve_vec() node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); ntype.gpu_fn = file_ns::gpu_shader_curve_vec; ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } /* **************** CURVE RGB ******************** */ -namespace blender::nodes::node_shader_curves_cc { +namespace blender::nodes::node_shader_curves_cc::rgb { static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b) { @@ -251,11 +259,18 @@ static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &bui builder.construct_and_set_matching_fn(*cumap); } -} // namespace blender::nodes::node_shader_curves_cc +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: implement */ + return get_input_value("Color", NodeItem::Type::Color4); +} +NODE_SHADER_MATERIALX_END + +} // namespace blender::nodes::node_shader_curves_cc::rgb void register_node_type_sh_curve_rgb() { - namespace file_ns = blender::nodes::node_shader_curves_cc; + namespace file_ns = blender::nodes::node_shader_curves_cc::rgb; static bNodeType ntype; @@ -266,13 +281,14 @@ void register_node_type_sh_curve_rgb() node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); ntype.gpu_fn = file_ns::gpu_shader_curve_rgb; ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } /* **************** CURVE FLOAT ******************** */ -namespace blender::nodes::node_shader_curves_cc { +namespace blender::nodes::node_shader_curves_cc::flt { static void sh_node_curve_float_declare(NodeDeclarationBuilder &b) { @@ -369,11 +385,18 @@ static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &b builder.construct_and_set_matching_fn(*cumap); } -} // namespace blender::nodes::node_shader_curves_cc +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: implement */ + return get_input_value("Value", NodeItem::Type::Float); +} +NODE_SHADER_MATERIALX_END + +} // namespace blender::nodes::node_shader_curves_cc::flt void register_node_type_sh_curve_float() { - namespace file_ns = blender::nodes::node_shader_curves_cc; + namespace file_ns = blender::nodes::node_shader_curves_cc::flt; static bNodeType ntype; @@ -384,6 +407,7 @@ void register_node_type_sh_curve_float() node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); ntype.gpu_fn = file_ns::gpu_shader_curve_float; ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.cc b/source/blender/nodes/shader/nodes/node_shader_emission.cc index 98b17ce5d99..5f2778c8cb5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_emission.cc +++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc @@ -24,6 +24,21 @@ static int node_shader_gpu_emission(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_emission", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + if (to_type_ != NodeItem::Type::EDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); + + NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF); + res.set_input("color", color * strength); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_emission_cc /* node type definition */ @@ -36,6 +51,7 @@ void register_node_type_sh_emission() sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_emission; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.cc b/source/blender/nodes/shader/nodes/node_shader_gamma.cc index e45bfd15674..8492b44fc91 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.cc +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.cc @@ -22,6 +22,13 @@ static int node_shader_gpu_gamma(GPUMaterial *mat, { return GPU_stack_link(mat, node, "node_gamma", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem color = get_input_value("Color", NodeItem::Type::Color4); + NodeItem gamma = get_input_value("Gamma", NodeItem::Type::Float); + return color ^ gamma; +} +NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_gamma_cc @@ -34,6 +41,7 @@ void register_node_type_sh_gamma() sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_gamma; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc index 0d5c7e6262b..afcef6cd59c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc +++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc @@ -30,6 +30,30 @@ static int gpu_shader_hue_sat(GPUMaterial *mat, return GPU_stack_link(mat, node, "hue_sat", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: implement fac */ + NodeItem hue = get_input_value("Hue", NodeItem::Type::Float); + NodeItem saturation = get_input_value("Saturation", NodeItem::Type::Float); + NodeItem value = get_input_value("Value", NodeItem::Type::Float); + NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + + /* Modifier to follow Cycles result */ + hue = hue - val(0.5f); + + NodeItem combine = create_node("combine3", NodeItem::Type::Vector3); + combine.set_input("in1", hue); + combine.set_input("in2", saturation); + combine.set_input("in3", value); + + NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3); + res.set_input("in", color); + res.set_input("amount", combine); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_hueSatVal_cc void register_node_type_sh_hue_sat() @@ -42,6 +66,7 @@ void register_node_type_sh_hue_sat() ntype.declare = file_ns::node_declare; blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.gpu_fn = file_ns::gpu_shader_hue_sat; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc index a095b9f63bb..ed0a520e974 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.cc +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -26,6 +26,14 @@ static int gpu_shader_invert(GPUMaterial *mat, return GPU_stack_link(mat, node, "invert", in, out); } +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, fac.val(1.0f) - color); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_invert_cc void register_node_type_sh_invert() @@ -37,6 +45,7 @@ void register_node_type_sh_invert() sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_invert; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc index b77eac00d82..41eac7dfbf1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc @@ -24,6 +24,17 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_light_falloff", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); + NodeItem smooth = get_input_value("Smooth", NodeItem::Type::Float); + + /* This node isn't supported by MaterialX. This formula was given from OSL shader code in Cycles + * node_light_falloff.osl. Considered ray_length=1.0f. */ + return strength * val(1.0f) / (smooth + val(1.0f)); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_light_falloff_cc /* node type definition */ @@ -37,6 +48,7 @@ void register_node_type_sh_light_falloff() ntype.declare = file_ns::node_declare; blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_light_falloff; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.cc b/source/blender/nodes/shader/nodes/node_shader_light_path.cc index 4b722d838d9..f3f3b314031 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_path.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc @@ -32,6 +32,19 @@ static int node_shader_gpu_light_path(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_light_path", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + /* This node isn't supported by MaterialX. Only default values returned. */ + if (STREQ(socket_out_->name, "Is Camera Ray")) { + return val(1.0f); + } + if (STREQ(socket_out_->name, "Ray Length")) { + return val(1.0f); + } + return val(0.0f); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_light_path_cc /* node type definition */ @@ -44,6 +57,7 @@ void register_node_type_sh_light_path() sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_light_path; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index 9f204dbf8f1..e2c8123d3fc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -442,6 +442,49 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui } } +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: Implement steps */ + + const NodeMapRange *map_range = static_cast(node_->storage); + NodeItem::Type type; + NodeItem value = empty(); + NodeItem from_min = empty(); + NodeItem from_max = empty(); + NodeItem to_min = empty(); + NodeItem to_max = empty(); + switch (map_range->data_type) { + case CD_PROP_FLOAT: + type = NodeItem::Type::Float; + value = get_input_value("Value", type); + from_min = get_input_value(1, type); + from_max = get_input_value(2, type); + to_min = get_input_value(3, type); + to_max = get_input_value(4, type); + break; + case CD_PROP_FLOAT3: + type = NodeItem::Type::Vector3; + value = get_input_value("Vector", type); + from_min = get_input_value(7, type); + from_max = get_input_value(8, type); + to_min = get_input_value(9, type); + to_max = get_input_value(10, type); + break; + default: + BLI_assert_unreachable(); + } + + NodeItem res = create_node("range", type); + res.set_input("in", value); + res.set_input("inlow", from_min); + res.set_input("inhigh", from_max); + res.set_input("outlow", to_min); + res.set_input("outhigh", to_max); + res.set_input("doclamp", val(bool(map_range->clamp))); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_map_range_cc void register_node_type_sh_map_range() @@ -461,5 +504,6 @@ void register_node_type_sh_map_range() ntype.gpu_fn = file_ns::gpu_shader_map_range; ntype.build_multi_function = file_ns::sh_node_map_range_build_multi_function; ntype.gather_link_search_ops = file_ns::node_map_range_gather_link_searches; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 5202c4fb422..aacf978c962 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -177,6 +177,170 @@ static void sh_node_math_build_multi_function(NodeMultiFunctionBuilder &builder) } } +NODE_SHADER_MATERIALX_BEGIN +{ + CLG_LogRef *LOG_MATERIALX_SHADER = materialx::LOG_MATERIALX_SHADER; + + /* TODO: finish some math operations */ + NodeMathOperation op = NodeMathOperation(node_->custom1); + NodeItem res = empty(); + + /* Single operand operations */ + NodeItem x = get_input_value(0, NodeItem::Type::Float); + /* TODO: Seems we have to use average if Vector or Color are added */ + + switch (op) { + case NODE_MATH_SINE: + res = x.sin(); + break; + case NODE_MATH_COSINE: + res = x.cos(); + break; + case NODE_MATH_TANGENT: + res = x.tan(); + break; + case NODE_MATH_ARCSINE: + res = x.asin(); + break; + case NODE_MATH_ARCCOSINE: + res = x.acos(); + break; + case NODE_MATH_ARCTANGENT: + res = x.atan(); + break; + case NODE_MATH_ROUND: + res = (x + val(0.5f)).floor(); + break; + case NODE_MATH_ABSOLUTE: + res = x.abs(); + break; + case NODE_MATH_FLOOR: + res = x.floor(); + break; + case NODE_MATH_CEIL: + res = x.ceil(); + break; + case NODE_MATH_FRACTION: + res = x % val(1.0f); + break; + case NODE_MATH_SQRT: + res = x.sqrt(); + break; + case NODE_MATH_INV_SQRT: + res = val(1.0f) / x.sqrt(); + break; + case NODE_MATH_SIGN: + res = x.sign(); + break; + case NODE_MATH_EXPONENT: + res = x.exp(); + break; + case NODE_MATH_RADIANS: + res = x * val(float(M_PI) / 180.0f); + break; + case NODE_MATH_DEGREES: + res = x * val(180.0f * float(M_1_PI)); + break; + case NODE_MATH_SINH: + res = x.sinh(); + break; + case NODE_MATH_COSH: + res = x.cosh(); + break; + case NODE_MATH_TANH: + res = x.tanh(); + break; + case NODE_MATH_TRUNC: + res = x.sign() * x.abs().floor(); + break; + + default: { + /* 2-operand operations */ + NodeItem y = get_input_value(1, NodeItem::Type::Float); + switch (op) { + case NODE_MATH_ADD: + res = x + y; + break; + case NODE_MATH_SUBTRACT: + res = x - y; + break; + case NODE_MATH_MULTIPLY: + res = x * y; + break; + case NODE_MATH_DIVIDE: + res = x / y; + break; + case NODE_MATH_POWER: + res = x ^ y; + break; + case NODE_MATH_LOGARITHM: + res = x.ln() / y.ln(); + break; + case NODE_MATH_MINIMUM: + res = x.min(y); + break; + case NODE_MATH_MAXIMUM: + res = x.max(y); + break; + case NODE_MATH_LESS_THAN: + res = x.if_else(NodeItem::CompareOp::Less, y, val(1.0f), val(0.0f)); + break; + case NODE_MATH_GREATER_THAN: + res = x.if_else(NodeItem::CompareOp::Greater, y, val(1.0f), val(0.0f)); + break; + case NODE_MATH_MODULO: + res = x % y; + break; + case NODE_MATH_ARCTAN2: + res = x.atan2(y); + break; + case NODE_MATH_SNAP: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_MATH_PINGPONG: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_MATH_FLOORED_MODULO: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + + default: { + /* 3-operand operations */ + NodeItem z = get_input_value(2, NodeItem::Type::Float); + switch (op) { + case NODE_MATH_WRAP: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_MATH_COMPARE: + res = z.if_else(NodeItem::CompareOp::Less, (x - y).abs(), val(1.0f), val(0.0f)); + break; + case NODE_MATH_MULTIPLY_ADD: + res = x * y + z; + break; + case NODE_MATH_SMOOTH_MIN: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + case NODE_MATH_SMOOTH_MAX: + CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); + break; + + default: + BLI_assert_unreachable(); + } + } + } + } + } + + bool clamp_output = node_->custom2 != 0; + if (clamp_output && res) { + res = res.clamp(); + } + + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_math_cc void register_node_type_sh_math() @@ -192,6 +356,7 @@ void register_node_type_sh_math() ntype.updatefunc = node_math_update; ntype.build_multi_function = file_ns::sh_node_math_build_multi_function; ntype.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index b6576c247f8..2a309546818 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -150,6 +150,13 @@ static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &build builder.construct_and_set_matching_fn(clamp, mix_type); } +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: Implement */ + return empty(); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_mix_rgb_cc void register_node_type_sh_mix_rgb() @@ -165,5 +172,6 @@ void register_node_type_sh_mix_rgb() ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function; ntype.gather_link_search_ops = nullptr; ntype.gather_add_node_search_ops = nullptr; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index f877a385280..eae8ca96526 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -23,6 +23,45 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_mix_shader", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem res = empty(); + switch (to_type_) { + 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_); + res.set_input("fg", shader1); + res.set_input("bg", shader2); + res.set_input("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; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_mix_shader_cc /* node type definition */ @@ -35,6 +74,7 @@ void register_node_type_sh_mix_shader() sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_mix_shader; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc index 9dffb5afc9c..0e54a44a174 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc @@ -122,6 +122,38 @@ static int gpu_shader_normal_map(GPUMaterial *mat, return true; } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeShaderNormalMap *normal_map_node = static_cast(node_->storage); + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); + + std::string space; + switch (normal_map_node->space) { + case SHD_SPACE_TANGENT: + space = "tangent"; + break; + case SHD_SPACE_OBJECT: + case SHD_SPACE_BLENDER_OBJECT: + space = "object"; + break; + case SHD_SPACE_WORLD: + case SHD_SPACE_BLENDER_WORLD: + /* World isn't supported, tangent space will be used */ + space = "tangent"; + break; + default: + BLI_assert_unreachable(); + } + + NodeItem res = create_node("normalmap", NodeItem::Type::Vector3); + res.set_input("in", color); + res.set_input("scale", strength); + res.set_input("space", val(space)); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_normal_map_cc /* node type definition */ @@ -139,6 +171,7 @@ void register_node_type_sh_normal_map() node_type_storage( &ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::gpu_shader_normal_map; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index 39b3d386138..db008c87262 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -43,6 +43,29 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, return true; } +NODE_SHADER_MATERIALX_BEGIN +{ + 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) { + surface.set_input("bsdf", bsdf); + } + if (edf) { + surface.set_input("edf", edf); + } + } + else { + surface = get_input_link("Surface", NodeItem::Type::SurfaceShader); + } + NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); + res.set_input("surfaceshader", surface); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_output_material_cc /* node type definition */ @@ -56,6 +79,7 @@ void register_node_type_sh_output_material() ntype.declare = file_ns::node_declare; ntype.add_ui_poll = object_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_material; + ntype.materialx_fn = file_ns::node_shader_materialx; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc index 333aefa3427..e7bb9c948e0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc @@ -27,6 +27,16 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat, return GPU_stack_link(mat, node, "rgbtobw", in, out); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem color = get_input_value("Color", NodeItem::Type::Color4); + + NodeItem res = create_node("luminance", NodeItem::Type::Color4); + res.set_input("in", color); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_rgb_to_bw_cc void register_node_type_sh_rgbtobw() @@ -38,6 +48,7 @@ void register_node_type_sh_rgbtobw() sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER); ntype.declare = file_ns::sh_node_rgbtobw_declare; ntype.gpu_fn = file_ns::gpu_shader_rgbtobw; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc index c19bb30f8d3..e566eb838f4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc @@ -68,6 +68,31 @@ static int gpu_shader_sepcolor(GPUMaterial *mat, return 0; } +NODE_SHADER_MATERIALX_BEGIN +{ + int mode = static_cast(node_->storage)->mode; + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + + NodeItem convert = empty(); + switch (mode) { + case NODE_COMBSEP_COLOR_RGB: + convert = color; + break; + case NODE_COMBSEP_COLOR_HSV: + case NODE_COMBSEP_COLOR_HSL: + /* NOTE: HSL is unsupported color model, using HSV instead */ + convert = create_node("rgbtohsv", NodeItem::Type::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; + return convert.extract(index); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_separate_color_cc void register_node_type_sh_sepcolor() @@ -83,6 +108,7 @@ void register_node_type_sh_sepcolor() node_type_storage( &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::gpu_shader_sepcolor; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } @@ -136,6 +162,36 @@ static int gpu_shader_combcolor(GPUMaterial *mat, return 0; } +NODE_SHADER_MATERIALX_BEGIN +{ + int mode = static_cast(node_->storage)->mode; + NodeItem red = get_input_value("Red", NodeItem::Type::Float); + NodeItem green = get_input_value("Green", NodeItem::Type::Float); + NodeItem blue = get_input_value("Blue", NodeItem::Type::Float); + + NodeItem combine = create_node("combine3", NodeItem::Type::Color3); + combine.set_input("in1", red); + combine.set_input("in2", green); + combine.set_input("in3", blue); + + NodeItem res = empty(); + switch (mode) { + case NODE_COMBSEP_COLOR_RGB: + res = combine; + break; + case NODE_COMBSEP_COLOR_HSV: + case NODE_COMBSEP_COLOR_HSL: + /* NOTE: HSL is unsupported color model, using HSV instead */ + res = create_node("hsvtorgb", NodeItem::Type::Color3); + res.set_input("in", combine); + break; + default: + BLI_assert_unreachable(); + } + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_combine_color_cc void register_node_type_sh_combcolor() @@ -151,6 +207,7 @@ void register_node_type_sh_combcolor() node_type_storage( &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::gpu_shader_combcolor; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index 5f1b06abb0b..bb4530c9fe1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -12,7 +12,7 @@ #include "NOD_multi_function.hh" -namespace blender::nodes::node_shader_sepcomb_xyz_cc { +namespace blender::nodes::node_shader_sepcomb_xyz_cc::sep { static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b) { @@ -90,11 +90,19 @@ static void sh_node_sepxyz_build_multi_function(NodeMultiFunctionBuilder &builde builder.set_matching_fn(separate_fn); } -} // namespace blender::nodes::node_shader_sepcomb_xyz_cc +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); +} +NODE_SHADER_MATERIALX_END + +} // namespace blender::nodes::node_shader_sepcomb_xyz_cc::sep void register_node_type_sh_sepxyz() { - namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc; + namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc::sep; static bNodeType ntype; @@ -102,11 +110,12 @@ void register_node_type_sh_sepxyz() ntype.declare = file_ns::sh_node_sepxyz_declare; ntype.gpu_fn = file_ns::gpu_shader_sepxyz; ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -namespace blender::nodes::node_shader_sepcomb_xyz_cc { +namespace blender::nodes::node_shader_sepcomb_xyz_cc::comb { static void sh_node_combxyz_declare(NodeDeclarationBuilder &b) { @@ -135,11 +144,25 @@ static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &build builder.set_matching_fn(fn); } -} // namespace blender::nodes::node_shader_sepcomb_xyz_cc +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem x = get_input_value("X", NodeItem::Type::Float); + NodeItem y = get_input_value("Y", NodeItem::Type::Float); + NodeItem z = get_input_value("Z", NodeItem::Type::Float); + + NodeItem res = create_node("combine3", NodeItem::Type::Vector3); + res.set_input("in1", x); + res.set_input("in2", y); + res.set_input("in3", z); + return res; +} +NODE_SHADER_MATERIALX_END + +} // namespace blender::nodes::node_shader_sepcomb_xyz_cc::comb void register_node_type_sh_combxyz() { - namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc; + namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc::comb; static bNodeType ntype; @@ -147,6 +170,7 @@ void register_node_type_sh_combxyz() ntype.declare = file_ns::sh_node_combxyz_declare; ntype.gpu_fn = file_ns::gpu_shader_combxyz; ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc index 468ae1ddf61..3ecfb83f048 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc @@ -102,6 +102,26 @@ static void sh_node_tex_checker_build_multi_function(NodeMultiFunctionBuilder &b builder.set_matching_fn(fn); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + NodeItem value1 = val(1.0f); + NodeItem value2 = val(0.0f); + if (STREQ(socket_out_->name, "Color")) { + value1 = get_input_value("Color1", NodeItem::Type::Color4); + value2 = get_input_value("Color2", NodeItem::Type::Color4); + } + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); + + vector = (vector * scale) % val(2.0f); + return (vector.extract(0).floor() + vector.extract(1).floor()) + .if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_checker_cc void register_node_type_sh_tex_checker() @@ -117,6 +137,7 @@ void register_node_type_sh_tex_checker() &ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_tex_checker; ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index 85e112906f6..ff9935c411c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -127,6 +127,13 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, return true; } +NODE_SHADER_MATERIALX_BEGIN +{ + /* TODO: Implement */ + return empty(); +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_environment_cc /* node type definition */ @@ -144,6 +151,7 @@ void register_node_type_sh_tex_environment() ntype.gpu_fn = file_ns::node_shader_gpu_tex_environment; ntype.labelfunc = node_image_label; blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE); + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index 98db1c7f9a9..0e8ecf3aba3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -11,6 +11,10 @@ #include "IMB_colormanagement.h" +#include "hydra/image.h" + +#include "DEG_depsgraph_query.h" + namespace blender::nodes::node_shader_tex_image_cc { static void sh_node_tex_image_declare(NodeDeclarationBuilder &b) @@ -172,6 +176,75 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, return true; } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); + + Image *image = (Image *)node_->id; + if (image) { + NodeTexImage *tex_image = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); + + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains + * pretty general code, so could be moved from bf_usd project. */ + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_image->iuser); + + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: add math to vector depending of tex_image->projection */ + + std::string filtertype; + switch (tex_image->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + std::string addressmode; + switch (tex_image->extension) { + case SHD_IMAGE_EXTENSION_REPEAT: + addressmode = "periodic"; + break; + case SHD_IMAGE_EXTENSION_EXTEND: + addressmode = "clamp"; + break; + case SHD_IMAGE_EXTENSION_CLIP: + addressmode = "constant"; + break; + case SHD_IMAGE_EXTENSION_MIRROR: + addressmode = "mirror"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); + res.set_input("file", image_path, NodeItem::Type::Filename); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + res.set_input("uaddressmode", val(addressmode)); + res.set_input("vaddressmode", val(addressmode)); + } + + if (STREQ(socket_out_->name, "Alpha")) { + res = res.extract(3); + } + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_image_cc void register_node_type_sh_tex_image() @@ -188,6 +261,7 @@ void register_node_type_sh_tex_image() ntype.gpu_fn = file_ns::node_shader_gpu_tex_image; ntype.labelfunc = node_image_label; blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE); + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index ac9df7770ab..bc6ff5a5cff 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -257,6 +257,25 @@ static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder builder.construct_and_set_matching_fn(storage.dimensions, storage.normalize); } +NODE_SHADER_MATERIALX_BEGIN +{ + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); + NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); + NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); + + NodeItem position = create_node("position", NodeItem::Type::Vector3); + position = position * scale; + + NodeItem res = create_node("fractal3d", NodeItem::Type::Color3); + res.set_input("position", position); + if (detail.value) { + res.set_input("octaves", val(int(detail.value->asA()))); + } + res.set_input("lacunarity", lacunarity); + return res; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_noise_cc void register_node_type_sh_tex_noise() @@ -274,6 +293,7 @@ void register_node_type_sh_tex_noise() ntype.gpu_fn = file_ns::node_shader_gpu_tex_noise; ntype.updatefunc = file_ns::node_shader_update_tex_noise; ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 0aedd24a662..bf072379705 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -316,6 +316,121 @@ static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &b builder.set_matching_fn(fn); } +NODE_SHADER_MATERIALX_BEGIN +{ + CLG_LogRef *LOG_MATERIALX_SHADER = materialx::LOG_MATERIALX_SHADER; + + /* TODO: finish some math operations */ + auto op = node_->custom1; + NodeItem res = empty(); + + /* Single operand operations */ + NodeItem x = get_input_value(0, NodeItem::Type::Vector3); + 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 % val(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, NodeItem::Type::Vector3); + 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, NodeItem::Type::Vector3); + 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; +} +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_vector_math_cc void register_node_type_sh_vect_math() @@ -332,6 +447,7 @@ void register_node_type_sh_vect_math() ntype.updatefunc = file_ns::node_shader_update_vector_math; ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function; ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From 9b836a944be7d43d7072d77c8c454ee10128cf26 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 14 Sep 2023 02:00:40 +0200 Subject: [PATCH 19/40] MaterialX: fix review comments ### Purpose Fix review comments ### Technical steps * Added comments * fixed includes * added ifdefs Pull Request: https://projects.blender.org/DagerD/blender/pulls/19 --- source/blender/blenkernel/BKE_node.h | 4 ++-- source/blender/io/usd/CMakeLists.txt | 1 + source/blender/io/usd/hydra/material.cc | 16 +++++++++++----- source/blender/nodes/shader/CMakeLists.txt | 5 +++-- .../blender/nodes/shader/materialx/node_item.h | 3 +++ source/blender/nodes/shader/node_shader_util.hh | 7 ++++++- .../nodes/shader/nodes/node_shader_add_shader.cc | 3 +++ .../nodes/shader/nodes/node_shader_blackbody.cc | 2 ++ .../nodes/shader/nodes/node_shader_brightness.cc | 2 ++ .../shader/nodes/node_shader_bsdf_diffuse.cc | 2 ++ .../shader/nodes/node_shader_bsdf_principled.cc | 2 ++ .../nodes/shader/nodes/node_shader_clamp.cc | 2 ++ .../nodes/shader/nodes/node_shader_color_ramp.cc | 2 ++ .../nodes/shader/nodes/node_shader_curves.cc | 6 ++++++ .../nodes/shader/nodes/node_shader_emission.cc | 2 ++ .../nodes/shader/nodes/node_shader_gamma.cc | 2 ++ .../nodes/shader/nodes/node_shader_hueSatVal.cc | 2 ++ .../nodes/shader/nodes/node_shader_invert.cc | 2 ++ .../shader/nodes/node_shader_light_falloff.cc | 2 ++ .../nodes/shader/nodes/node_shader_light_path.cc | 2 ++ .../nodes/shader/nodes/node_shader_map_range.cc | 2 ++ .../nodes/shader/nodes/node_shader_math.cc | 2 ++ .../nodes/shader/nodes/node_shader_mix_rgb.cc | 2 ++ .../nodes/shader/nodes/node_shader_mix_shader.cc | 2 ++ .../nodes/shader/nodes/node_shader_normal_map.cc | 2 ++ .../shader/nodes/node_shader_output_material.cc | 2 ++ .../nodes/shader/nodes/node_shader_rgb_to_bw.cc | 2 ++ .../shader/nodes/node_shader_sepcomb_color.cc | 4 ++++ .../shader/nodes/node_shader_sepcomb_xyz.cc | 4 ++++ .../shader/nodes/node_shader_tex_checker.cc | 2 ++ .../shader/nodes/node_shader_tex_environment.cc | 2 ++ .../nodes/shader/nodes/node_shader_tex_image.cc | 2 ++ .../nodes/shader/nodes/node_shader_tex_noise.cc | 2 ++ .../shader/nodes/node_shader_vector_math.cc | 2 ++ 34 files changed, 91 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index e14067f138e..3e79e0547d0 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -225,7 +225,7 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, struct bNodeExecData *execdata, struct GPUNodeStack *in, struct GPUNodeStack *out); -typedef void (*NodeMaterialXExecFunction)(void *data, +typedef void (*NodeMaterialXFunction)(void *data, struct bNode *node, struct bNodeSocket *out); @@ -343,7 +343,7 @@ typedef struct bNodeType { /* gpu */ NodeGPUExecFunction gpu_fn; /* MaterialX */ - NodeMaterialXExecFunction materialx_fn; + NodeMaterialXFunction materialx_fn; /* Get an instance of this node's compositor operation. Freeing the instance is the * responsibility of the caller. */ diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index d913410f834..e1aeffb5349 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -210,6 +210,7 @@ if(WITH_OPENVDB) endif() if(WITH_MATERIALX) + add_definitions(-DWITH_MATERIALX) list(APPEND LIB MaterialXCore) endif() diff --git a/source/blender/io/usd/hydra/material.cc b/source/blender/io/usd/hydra/material.cc index e986e6e2016..a992dbdbfa3 100644 --- a/source/blender/io/usd/hydra/material.cc +++ b/source/blender/io/usd/hydra/material.cc @@ -12,8 +12,10 @@ #include #include -#include -#include +#ifdef WITH_MATERIALX +# include +# include +#endif #include "MEM_guardedalloc.h" @@ -33,8 +35,9 @@ #include "intern/usd_exporter_context.h" #include "intern/usd_writer_material.h" -#include "shader/materialx/material.h" - +#ifdef WITH_MATERIALX +# include "shader/materialx/material.h" +#endif namespace blender::io::hydra { MaterialData::MaterialData(HydraSceneDelegate *scene_delegate, @@ -73,6 +76,7 @@ void MaterialData::init() image_cache_file_path()}; /* Create USD material. */ pxr::UsdShadeMaterial usd_material; +#ifdef WITH_MATERIALX if (scene_delegate_->use_materialx) { MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx( scene_delegate_->depsgraph, (Material *)id); @@ -84,7 +88,9 @@ void MaterialData::init() } } } - else { + else +#endif + { usd_material = usd::create_usd_material(export_context, material_path, (Material *)id, "st"); } diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 98e9f7db99a..25990bdcd1a 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -16,6 +16,7 @@ set(INC ../../makesrna ../../render ../../windowmanager + ../../../../intern/clog ../../../../intern/sky/include # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna @@ -24,8 +25,7 @@ set(INC if(WITH_HYDRA) list(APPEND INC ../../io/usd - ../../../../intern/clog -) + ) add_definitions(-DWITH_HYDRA) endif() @@ -145,6 +145,7 @@ set(LIB ) if(WITH_MATERIALX) + add_definitions(-DWITH_MATERIALX) list(APPEND SRC materialx/material.cc materialx/node_item.cc diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index f9e45822f66..704e70832a4 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -8,6 +8,9 @@ namespace blender::nodes::materialx { +/* 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. */ class NodeItem { public: enum class Type { diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index a19b849136e..fce47c0e7d7 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -22,7 +22,12 @@ #include "node_shader_register.hh" -#include "materialx/node_parser.h" +#ifdef WITH_MATERIALX +# include "materialx/node_parser.h" +#else +# define NODE_SHADER_MATERIALX_BEGIN NodeMaterialXFunction node_shader_materialx = nullptr; +# define NODE_SHADER_MATERIALX_END +#endif struct bContext; typedef struct bContext bContext; diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc index ae520a0131e..7f5ba0162d7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc @@ -23,6 +23,7 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem res = empty(); switch (to_type_) { @@ -55,6 +56,7 @@ NODE_SHADER_MATERIALX_BEGIN } return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_add_shader_cc @@ -69,6 +71,7 @@ void register_node_type_sh_add_shader() sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_add_shader; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc index a84b0d3414e..d88ae1d5d54 100644 --- a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc +++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc @@ -32,6 +32,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: This node doesn't have an implementation in MaterialX 1.38.6. * It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8. @@ -43,6 +44,7 @@ NODE_SHADER_MATERIALX_BEGIN * return res; */ return empty(); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_blackbody_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.cc b/source/blender/nodes/shader/nodes/node_shader_brightness.cc index 1172ebf1b92..1abc0c783ad 100644 --- a/source/blender/nodes/shader/nodes/node_shader_brightness.cc +++ b/source/blender/nodes/shader/nodes/node_shader_brightness.cc @@ -24,6 +24,7 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem bright = get_input_value("Bright", NodeItem::Type::Float); @@ -32,6 +33,7 @@ NODE_SHADER_MATERIALX_BEGIN /* This formula was given from OSL shader code in Cycles. */ return (bright + color * (contrast + val(1.0f)) - contrast * val(0.5f)).max(val(0.0f)); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_brightness_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index 3e05d4fd202..353edc5ef58 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -35,6 +35,7 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { if (to_type_ != NodeItem::Type::BSDF) { return empty(); @@ -52,6 +53,7 @@ NODE_SHADER_MATERIALX_BEGIN } return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_bsdf_diffuse_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index 55d55a8ca37..3c31389a084 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -254,6 +254,7 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node) } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { if (to_type_ != NodeItem::Type::SurfaceShader) { /* TODO: implement for BSDF and EDF */ @@ -344,6 +345,7 @@ NODE_SHADER_MATERIALX_BEGIN return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_bsdf_principled_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index 576b8eebee4..f294d8de7f8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -71,6 +71,7 @@ static void sh_node_clamp_build_multi_function(NodeMultiFunctionBuilder &builder } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { auto type = node_->custom1; NodeItem value = get_input_value("Value", NodeItem::Type::Float); @@ -87,6 +88,7 @@ NODE_SHADER_MATERIALX_BEGIN } return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_clamp_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc index dbac50fa0e0..1f4aace65c3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -137,10 +137,12 @@ static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilde } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: Implement */ return empty(); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_color_ramp_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index 046d16d84b1..a59b99e7c4f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -110,10 +110,12 @@ static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &bui } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: implement */ return get_input_value("Value", NodeItem::Type::Vector3); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_curves_cc::vec @@ -260,10 +262,12 @@ static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &bui } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: implement */ return get_input_value("Color", NodeItem::Type::Color4); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_curves_cc::rgb @@ -386,10 +390,12 @@ static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &b } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: implement */ return get_input_value("Value", NodeItem::Type::Float); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_curves_cc::flt diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.cc b/source/blender/nodes/shader/nodes/node_shader_emission.cc index 5f2778c8cb5..dbd56fedc40 100644 --- a/source/blender/nodes/shader/nodes/node_shader_emission.cc +++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc @@ -25,6 +25,7 @@ static int node_shader_gpu_emission(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { if (to_type_ != NodeItem::Type::EDF) { return empty(); @@ -37,6 +38,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("color", color * strength); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_emission_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.cc b/source/blender/nodes/shader/nodes/node_shader_gamma.cc index 8492b44fc91..13964192252 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.cc +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.cc @@ -23,11 +23,13 @@ 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 { 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 } // namespace blender::nodes::node_shader_gamma_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc index afcef6cd59c..2c00df75e91 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc +++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc @@ -31,6 +31,7 @@ static int gpu_shader_hue_sat(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: implement fac */ NodeItem hue = get_input_value("Hue", NodeItem::Type::Float); @@ -52,6 +53,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("amount", combine); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_hueSatVal_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc index ed0a520e974..693950aa85d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.cc +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -27,11 +27,13 @@ static int gpu_shader_invert(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem fac = get_input_value("Fac", NodeItem::Type::Float); NodeItem color = get_input_value("Color", NodeItem::Type::Color3); return fac.blend(color, fac.val(1.0f) - color); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_invert_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc index 41eac7dfbf1..bd5db49387f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc @@ -25,6 +25,7 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); NodeItem smooth = get_input_value("Smooth", NodeItem::Type::Float); @@ -33,6 +34,7 @@ NODE_SHADER_MATERIALX_BEGIN * node_light_falloff.osl. Considered ray_length=1.0f. */ return strength * val(1.0f) / (smooth + val(1.0f)); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_light_falloff_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.cc b/source/blender/nodes/shader/nodes/node_shader_light_path.cc index f3f3b314031..654688190dc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_path.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc @@ -33,6 +33,7 @@ static int node_shader_gpu_light_path(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* This node isn't supported by MaterialX. Only default values returned. */ if (STREQ(socket_out_->name, "Is Camera Ray")) { @@ -43,6 +44,7 @@ NODE_SHADER_MATERIALX_BEGIN } return val(0.0f); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_light_path_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index e2c8123d3fc..4823208e6e1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -443,6 +443,7 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: Implement steps */ @@ -483,6 +484,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("doclamp", val(bool(map_range->clamp))); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_map_range_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index aacf978c962..437b830d6a3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -178,6 +178,7 @@ static void sh_node_math_build_multi_function(NodeMultiFunctionBuilder &builder) } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { CLG_LogRef *LOG_MATERIALX_SHADER = materialx::LOG_MATERIALX_SHADER; @@ -339,6 +340,7 @@ NODE_SHADER_MATERIALX_BEGIN return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_math_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index 2a309546818..322e06d74c3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -151,10 +151,12 @@ static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &build } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: Implement */ return empty(); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_mix_rgb_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index eae8ca96526..434b54515f0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -24,6 +24,7 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem res = empty(); switch (to_type_) { @@ -60,6 +61,7 @@ NODE_SHADER_MATERIALX_BEGIN } return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_mix_shader_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc index 0e54a44a174..44c162913f2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc @@ -123,6 +123,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeShaderNormalMap *normal_map_node = static_cast(node_->storage); NodeItem color = get_input_value("Color", NodeItem::Type::Color3); @@ -152,6 +153,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("space", val(space)); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_normal_map_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index db008c87262..1167bfb9677 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -44,6 +44,7 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem bsdf = get_input_link("Surface", NodeItem::Type::BSDF); NodeItem edf = get_input_link("Surface", NodeItem::Type::EDF); @@ -64,6 +65,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("surfaceshader", surface); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_output_material_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc index e7bb9c948e0..77407b3b515 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc @@ -28,6 +28,7 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem color = get_input_value("Color", NodeItem::Type::Color4); @@ -35,6 +36,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("in", color); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_rgb_to_bw_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc index e566eb838f4..e82856ab18e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc @@ -69,6 +69,7 @@ static int gpu_shader_sepcolor(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { int mode = static_cast(node_->storage)->mode; NodeItem color = get_input_value("Color", NodeItem::Type::Color3); @@ -91,6 +92,7 @@ NODE_SHADER_MATERIALX_BEGIN int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2; return convert.extract(index); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_separate_color_cc @@ -163,6 +165,7 @@ static int gpu_shader_combcolor(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { int mode = static_cast(node_->storage)->mode; NodeItem red = get_input_value("Red", NodeItem::Type::Float); @@ -190,6 +193,7 @@ NODE_SHADER_MATERIALX_BEGIN } return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_combine_color_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index bb4530c9fe1..b9f0b568e51 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -91,11 +91,13 @@ static void sh_node_sepxyz_build_multi_function(NodeMultiFunctionBuilder &builde } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { 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); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_sepcomb_xyz_cc::sep @@ -145,6 +147,7 @@ static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &build } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem x = get_input_value("X", NodeItem::Type::Float); NodeItem y = get_input_value("Y", NodeItem::Type::Float); @@ -156,6 +159,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("in3", z); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_sepcomb_xyz_cc::comb diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc index 3ecfb83f048..40dd136fafc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc @@ -103,6 +103,7 @@ static void sh_node_tex_checker_build_multi_function(NodeMultiFunctionBuilder &b } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); if (!vector) { @@ -120,6 +121,7 @@ NODE_SHADER_MATERIALX_BEGIN return (vector.extract(0).floor() + vector.extract(1).floor()) .if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_tex_checker_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index ff9935c411c..cc828b8bdf4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -128,10 +128,12 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { /* TODO: Implement */ return empty(); } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_tex_environment_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index 0e8ecf3aba3..c683db52e4a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -177,6 +177,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); @@ -243,6 +244,7 @@ NODE_SHADER_MATERIALX_BEGIN } return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_tex_image_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index bc6ff5a5cff..8fe27900be4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -258,6 +258,7 @@ static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); @@ -274,6 +275,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("lacunarity", lacunarity); return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_tex_noise_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index bf072379705..fc1d5e91719 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -317,6 +317,7 @@ static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &b } NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX { CLG_LogRef *LOG_MATERIALX_SHADER = materialx::LOG_MATERIALX_SHADER; @@ -429,6 +430,7 @@ NODE_SHADER_MATERIALX_BEGIN return res; } +#endif NODE_SHADER_MATERIALX_END } // namespace blender::nodes::node_shader_vector_math_cc -- 2.30.2 From 1bc2f5c12523255a0638f632af08c5d16e65ef4c Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Thu, 14 Sep 2023 05:29:20 +0300 Subject: [PATCH 20/40] Adjusted BSDFPrincipled --- .../nodes/node_shader_bsdf_principled.cc | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index ad007aab5eb..d15b7cf2783 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -296,7 +296,7 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float); NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3); - NodeItem subsurface_color = get_input_value("Subsurface Color", NodeItem::Type::Color3); + NodeItem subsurface_scale = get_input_value("Subsurface Scale", NodeItem::Type::Float); NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float); NodeItem specular = get_input_value("Specular", NodeItem::Type::Float); @@ -311,8 +311,8 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float); // sheen_tint = get_input_value("Sheen Tint"); - NodeItem clearcoat = get_input_value("Clearcoat", NodeItem::Type::Float); - NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness", NodeItem::Type::Float); + NodeItem coat = get_input_value("Coat", NodeItem::Type::Float); + NodeItem coat_roughness = get_input_value("Coat Roughness", NodeItem::Type::Float); NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); @@ -325,9 +325,11 @@ NODE_SHADER_MATERIALX_BEGIN // transparency = 1.0 - alpha NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3); + NodeItem coat_normal = get_input_link("Coat Normal", NodeItem::Type::Vector3); NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); + subsurface_radius = subsurface_radius * subsurface_scale; + /* Creating standard_surface */ NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader); res.set_input("base", val(1.0f)); @@ -353,7 +355,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("transmission_extra_roughness", roughness); res.set_input("subsurface", subsurface); - res.set_input("subsurface_color", subsurface_color); + res.set_input("subsurface_color", base_color); res.set_input("subsurface_radius", subsurface_radius); res.set_input("subsurface_anisotropy", anisotropic); @@ -361,14 +363,14 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("sheen_color", base_color); res.set_input("sheen_roughness", roughness); - res.set_input("coat", clearcoat); + res.set_input("coat", coat); res.set_input("coat_color", base_color); - res.set_input("coat_roughness", clearcoat_roughness); + res.set_input("coat_roughness", coat_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 (coat_normal) { + res.set_input("coat_normal", coat_normal); } res.set_input("emission", emission_strength); -- 2.30.2 From cbc1e652ab8ce5bfdfaa9a4575cc209d99d303b6 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 14 Sep 2023 16:54:53 +0200 Subject: [PATCH 21/40] MaterialX: add shader nodes ### Purpose Add shader nodes ### Technical steps Added nodes: * TranslucentBSDF * Subsurface scattering * SheenBSDF Pull Request: https://projects.blender.org/DagerD/blender/pulls/21 --- .../shader/nodes/node_shader_bsdf_sheen.cc | 24 ++++++++++++++++ .../nodes/node_shader_bsdf_translucent.cc | 21 ++++++++++++++ .../node_shader_subsurface_scattering.cc | 28 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc index dcd33d5904c..27bf2229129 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc @@ -47,6 +47,29 @@ static int node_shader_gpu_bsdf_sheen(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_sheen", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem res = create_node("sheen_bsdf", NodeItem::Type::BSDF); + res.set_input("color", color); + res.set_input("weight", roughness); + res.set_input("roughness", roughness); + if (normal) { + res.set_input("normal", normal); + } + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_sheen_cc /* node type definition */ @@ -62,6 +85,7 @@ void register_node_type_sh_bsdf_sheen() ntype.initfunc = file_ns::node_shader_init_sheen; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_sheen; ntype.draw_buttons = file_ns::node_shader_buts_sheen; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index d94e2b89a85..ed787b20161 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -29,6 +29,26 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem res = create_node("translucent_bsdf", NodeItem::Type::BSDF); + res.set_input("color", color); + if (normal) { + res.set_input("normal", normal); + } + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_translucent_cc /* node type definition */ @@ -42,6 +62,7 @@ void register_node_type_sh_bsdf_translucent() ntype.declare = file_ns::node_declare; ntype.add_ui_poll = object_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_translucent; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc index c3cbf550a40..85eeb92aadb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc @@ -77,6 +77,33 @@ static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *no } } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: IOR and Subsurface Method isn't supported for this node in MaterialX. */ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); + NodeItem radius = get_input_value("Radius", NodeItem::Type::Vector3); + NodeItem anisotropy = get_input_value("Anisotropy", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem res = create_node("subsurface_bsdf", NodeItem::Type::BSDF); + res.set_input("weight", val(1.0f)); + res.set_input("color", color); + res.set_input("radius", radius * scale); + res.set_input("anisotropy", anisotropy); + if (normal) { + res.set_input("normal", normal); + } + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_subsurface_scattering_cc /* node type definition */ @@ -95,6 +122,7 @@ void register_node_type_sh_subsurface_scattering() ntype.initfunc = file_ns::node_shader_init_subsurface_scattering; ntype.gpu_fn = file_ns::node_shader_gpu_subsurface_scattering; ntype.updatefunc = file_ns::node_shader_update_subsurface_scattering; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From 3cdecebaf0e377d303c6ecb2caade7fa98cee151 Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Fri, 15 Sep 2023 19:55:14 +0200 Subject: [PATCH 22/40] MaterialX: Implement export of Input nodes ### Purpose Add support for Input nodes. ### Technical steps Implemented get_value_default, get_output_default. Fixed type conversion issue. Now type is converted even if a node is already in the graph. Added: * RGB * Value Partially implemented: * Geometry * Object Info * Texture Coordinate * UVMap * Color Attribute * Wireframe Not implemented: * Ambient Occlusion * Attribute * Bevel * Camera Data * Fresnel * Curves Info * Layer Weight * Particle Info * Point Info * Tangent Pull Request: https://projects.blender.org/DagerD/blender/pulls/20 --- .../nodes/shader/materialx/node_parser.cc | 42 +++++++++++-------- .../nodes/shader/materialx/node_parser.h | 4 +- .../nodes/node_shader_ambient_occlusion.cc | 16 +++++++ .../shader/nodes/node_shader_attribute.cc | 11 +++++ .../nodes/shader/nodes/node_shader_bevel.cc | 10 +++++ .../nodes/shader/nodes/node_shader_camera.cc | 10 +++++ .../nodes/shader/nodes/node_shader_fresnel.cc | 11 +++++ .../shader/nodes/node_shader_geometry.cc | 28 +++++++++++++ .../shader/nodes/node_shader_hair_info.cc | 10 +++++ .../shader/nodes/node_shader_layer_weight.cc | 11 +++++ .../shader/nodes/node_shader_object_info.cc | 29 +++++++++++++ .../shader/nodes/node_shader_particle_info.cc | 10 +++++ .../shader/nodes/node_shader_point_info.cc | 10 +++++ .../nodes/shader/nodes/node_shader_rgb.cc | 12 ++++++ .../nodes/shader/nodes/node_shader_tangent.cc | 10 +++++ .../shader/nodes/node_shader_tex_coord.cc | 28 +++++++++++++ .../nodes/shader/nodes/node_shader_uvmap.cc | 12 ++++++ .../nodes/shader/nodes/node_shader_value.cc | 12 ++++++ .../shader/nodes/node_shader_vertex_color.cc | 11 +++++ .../shader/nodes/node_shader_wireframe.cc | 10 +++++ 20 files changed, 279 insertions(+), 18 deletions(-) diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index 357a27cacbb..297d39aec01 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -33,20 +33,18 @@ NodeItem NodeParser::compute_full() /* Checking if node was already computed */ res.node = graph_->getNode(node_name()); - if (res.node) { - return res; - } + if (!res.node) { + CLOG_INFO(LOG_MATERIALX_SHADER, + 1, + "%s [%d] => %s", + node_->name, + node_->typeinfo->type, + NodeItem::type(to_type_).c_str()); - CLOG_INFO(LOG_MATERIALX_SHADER, - 1, - "%s [%d] => %s", - node_->name, - node_->typeinfo->type, - NodeItem::type(to_type_).c_str()); - - res = compute(); - if (res.node) { - res.node->setName(node_name()); + res = compute(); + if (res.node) { + res.node->setName(node_name()); + } } if (NodeItem::is_arithmetic(to_type_)) { res = res.convert(to_type_); @@ -73,12 +71,12 @@ NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type typ NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) { - return get_input_default(node_->input_by_identifier(name), to_type); + return get_default(node_->input_by_identifier(name), to_type); } NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type) { - return get_input_default(node_->input_socket(index), to_type); + return get_default(node_->input_socket(index), to_type); } NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type) @@ -101,6 +99,16 @@ NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type) return get_input_value(node_->input_socket(index), to_type); } +NodeItem NodeParser::get_output_default(const std::string &name, NodeItem::Type to_type) +{ + return get_default(node_->output_by_identifier(name), to_type); +} + +NodeItem NodeParser::get_output_default(int index, NodeItem::Type to_type) +{ + return get_default(node_->output_socket(index), to_type); +} + NodeItem NodeParser::empty() const { return NodeItem(graph_); @@ -117,7 +125,7 @@ NodeItem NodeParser::texcoord_node() return res; } -NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type) +NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_type) { NodeItem res = empty(); switch (socket.type) { @@ -180,7 +188,7 @@ NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type t { NodeItem res = get_input_link(socket, to_type); if (!res) { - res = get_input_default(socket, to_type); + res = get_default(socket, to_type); } return res; } diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index c0e6d6952f0..464c92c0e64 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -42,6 +42,8 @@ class NodeParser { NodeItem create_node(const std::string &category, NodeItem::Type type); NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); NodeItem get_input_default(int index, NodeItem::Type to_type); + NodeItem get_output_default(const std::string &name, NodeItem::Type to_type); + NodeItem get_output_default(int index, NodeItem::Type to_type); NodeItem get_input_link(const std::string &name, NodeItem::Type to_type); NodeItem get_input_link(int index, NodeItem::Type to_type); NodeItem get_input_value(const std::string &name, NodeItem::Type to_type); @@ -51,7 +53,7 @@ class NodeParser { NodeItem texcoord_node(); private: - NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); + NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type); NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type); NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type); }; diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc index 7b14d937acc..cfb12be235d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc @@ -55,6 +55,21 @@ static void node_shader_init_ambient_occlusion(bNodeTree * /*ntree*/, bNode *nod node->custom2 = 0; } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* TODO: observed crash while rendering MaterialX_v1_38_6::ExceptionShaderGenError */ + /* + * NodeItem maxdistance = get_input_value("Distance", NodeItem::Type::Float); + * NodeItem res = create_node("ambientocclusion", NodeItem::Type::Float); + * res.set_input("coneangle", val(90.0f)); + * res.set_input("maxdistance", maxdistance); + */ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_ambient_occlusion_cc /* node type definition */ @@ -69,6 +84,7 @@ void register_node_type_sh_ambient_occlusion() ntype.draw_buttons = file_ns::node_shader_buts_ambient_occlusion; ntype.initfunc = file_ns::node_shader_init_ambient_occlusion; ntype.gpu_fn = file_ns::node_shader_gpu_ambient_occlusion; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.cc b/source/blender/nodes/shader/nodes/node_shader_attribute.cc index 3225af64925..d0ebd5ef222 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.cc +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc @@ -77,6 +77,16 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, return 1; } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* TODO: some outputs expected be implemented within the next iteration (see nodedef + * ) */ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_attribute_cc /* node type definition */ @@ -93,6 +103,7 @@ void register_node_type_sh_attribute() node_type_storage( &ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_attribute; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.cc b/source/blender/nodes/shader/nodes/node_shader_bevel.cc index 7692dcc932f..b17495bcb58 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bevel.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc @@ -39,6 +39,15 @@ static int gpu_shader_bevel(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bevel", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: This node doesn't have an implementation in MaterialX.*/ + return get_input_link("Normal", NodeItem::Type::Vector3); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bevel_cc /* node type definition */ @@ -53,6 +62,7 @@ void register_node_type_sh_bevel() ntype.draw_buttons = file_ns::node_shader_buts_bevel; ntype.initfunc = file_ns::node_shader_init_bevel; ntype.gpu_fn = file_ns::gpu_shader_bevel; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.cc b/source/blender/nodes/shader/nodes/node_shader_camera.cc index 27ce37f60eb..65496d1fd54 100644 --- a/source/blender/nodes/shader/nodes/node_shader_camera.cc +++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc @@ -26,6 +26,15 @@ static int gpu_shader_camera(GPUMaterial *mat, return GPU_stack_link(mat, node, "camera", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: This node doesn't have an implementation in MaterialX.*/ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_camera_cc void register_node_type_sh_camera() @@ -37,6 +46,7 @@ void register_node_type_sh_camera() sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_camera; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.cc b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc index 4a17c0ee343..cfd73b30f09 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.cc +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc @@ -26,6 +26,16 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_fresnel", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* TODO: some outputs expected be implemented within the next iteration (see nodedef + * ) */ + return get_input_value("IOR", NodeItem::Type::Float); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_fresnel_cc /* node type definition */ @@ -38,6 +48,7 @@ void register_node_type_sh_fresnel() sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_fresnel; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.cc b/source/blender/nodes/shader/nodes/node_shader_geometry.cc index 6f04416f6fd..651d6f4c390 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.cc +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc @@ -58,6 +58,33 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, return success; } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: Some outputs don't have an implementation in MaterialX.*/ + NodeItem res = empty(); + std::string name = socket_out_->name; + + if (name == "Position") { + res = create_node("position", NodeItem::Type::Vector3); + res.set_input("space", val(std::string("world"))); + } + else if (name == "Normal") { + res = create_node("normal", NodeItem::Type::Vector3); + res.set_input("space", val(std::string("world"))); + } + else if (ELEM(name, "Tangent", "True Normal")) { + res = create_node("tangent", NodeItem::Type::Vector3); + res.set_input("space", val(std::string("world"))); + } + else { + res = get_output_default(name, NodeItem::Type::Any); + } + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_geometry_cc /* node type definition */ @@ -70,6 +97,7 @@ void register_node_type_sh_geometry() sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_geometry; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.cc b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc index 36f97dcb06b..fe4f9b21b08 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hair_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc @@ -29,6 +29,15 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: This node doesn't have an implementation in MaterialX.*/ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_hair_info_cc /* node type definition */ @@ -41,6 +50,7 @@ void register_node_type_sh_hair_info() sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Curves Info", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_hair_info; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc index f92dff8cae9..c39832f6e4e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc @@ -27,6 +27,16 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_layer_weight", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* TODO: some outputs expected be implemented partially within the next iteration (see nodedef + * ) */ + return get_input_link("Blend", NodeItem::Type::Float); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_layer_weight_cc /* node type definition */ @@ -39,6 +49,7 @@ void register_node_type_sh_layer_weight() sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_layer_weight; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.cc b/source/blender/nodes/shader/nodes/node_shader_object_info.cc index 57ab75feb28..44d6286085a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc @@ -30,6 +30,34 @@ static int node_shader_gpu_object_info(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_constant(&index)); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: Some outputs don't have an implementation in MaterialX.*/ + NodeItem res = empty(); + std::string name = socket_out_->name; + + if (name == "Location") { + res = create_node("position", NodeItem::Type::Vector3); + res.set_input("space", val(std::string("world"))); + } + /* TODO: This node doesn't have an implementation in MaterialX. + * It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8. + * if (name=="Random") { + * res = create_node("randomfloat", NodeItem::Type::Float); + * res.set_input("in", val(0.0)); + * res.set_input("min", val(0.0)); + * res.set_input("max", val(1.0)); + * res.set_input("seed", val(0)); + *}*/ + else { + res = get_output_default(name, NodeItem::Type::Any); + } + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_object_info_cc void register_node_type_sh_object_info() @@ -41,6 +69,7 @@ void register_node_type_sh_object_info() sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_object_info; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc index c188c0f10f3..d194fb56769 100644 --- a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc @@ -34,6 +34,15 @@ static int gpu_shader_particle_info(GPUMaterial *mat, return GPU_stack_link(mat, node, "particle_info", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: This node doesn't have an implementation in MaterialX.*/ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_particle_info_cc /* node type definition */ @@ -46,6 +55,7 @@ void register_node_type_sh_particle_info() sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_particle_info; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_point_info.cc b/source/blender/nodes/shader/nodes/node_shader_point_info.cc index 4482e3cbca2..69ce2c94006 100644 --- a/source/blender/nodes/shader/nodes/node_shader_point_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_point_info.cc @@ -22,6 +22,15 @@ static int node_shader_gpu_point_info(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_point_info", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: This node doesn't have an implementation in MaterialX.*/ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_point_info_cc /* node type definition */ @@ -34,6 +43,7 @@ void register_node_type_sh_point_info() sh_node_type_base(&ntype, SH_NODE_POINT_INFO, "Point Info", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_point_info; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb.cc index 4d268e74b41..5f84b9f8c9e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc @@ -26,6 +26,17 @@ static int gpu_shader_rgb(GPUMaterial *mat, return GPU_link(mat, "set_rgba", GPU_uniform(value), &out->link); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem color = get_output_default("Color", NodeItem::Type::Color4); + NodeItem res = create_node("constant", NodeItem::Type::Color4); + res.set_input("value", color); + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_rgb_cc void register_node_type_sh_rgb() @@ -37,6 +48,7 @@ void register_node_type_sh_rgb() sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_rgb; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.cc b/source/blender/nodes/shader/nodes/node_shader_tangent.cc index 644c7fb8754..fb93a8956d8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tangent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc @@ -86,6 +86,15 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tangent", in, out, orco); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* TODO: This node doesn't have an implementation in MaterialX.*/ + return get_output_default(socket_out_->name, NodeItem::Type::Vector3); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tangent_cc /* node type definition */ @@ -103,6 +112,7 @@ void register_node_type_sh_tangent() ntype.gpu_fn = file_ns::node_shader_gpu_tangent; node_type_storage( &ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage); + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc index 875fcf74607..177d235077f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc @@ -71,6 +71,33 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, return 1; } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: Some outputs don't have an implementation in MaterialX.*/ + NodeItem res = empty(); + std::string name = socket_out_->name; + + if (ELEM(name, "Generated", "UV")) { + res = texcoord_node(); + } + else if (name == "Normal") { + res = create_node("normal", NodeItem::Type::Vector3); + res.set_input("space", val(std::string("world"))); + } + else if (name == "Object") { + res = create_node("position", NodeItem::Type::Vector3); + res.set_input("space", val(std::string("world"))); + } + else { + res = get_output_default(name, NodeItem::Type::Any); + } + + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_coord_cc /* node type definition */ @@ -84,6 +111,7 @@ void register_node_type_sh_tex_coord() ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_shader_buts_tex_coord; ntype.gpu_fn = file_ns::node_shader_gpu_tex_coord; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc index 543400d8e28..6b19a7982d3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc @@ -67,6 +67,17 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat, return 1; } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NODE: "From Instances" not implemented + * UV selection not implemented + */ + return texcoord_node(); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_uvmap_cc /* node type definition */ @@ -84,6 +95,7 @@ void register_node_type_sh_uvmap() node_type_storage( &ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_uvmap; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 072fdc2d917..01663d11288 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -38,6 +38,17 @@ static void sh_node_value_build_multi_function(NodeMultiFunctionBuilder &builder builder.construct_and_set_matching_fn>(value->value); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem value = get_output_default("Value", NodeItem::Type::Float); + NodeItem res = create_node("constant", NodeItem::Type::Float); + res.set_input("value", value); + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_value_cc void register_node_type_sh_value() @@ -50,6 +61,7 @@ void register_node_type_sh_value() ntype.declare = file_ns::sh_node_value_declare; ntype.gpu_fn = file_ns::gpu_shader_value; ntype.build_multi_function = file_ns::sh_node_value_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc index 83b64c504e1..0664aa1b31e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc @@ -67,6 +67,16 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* TODO: some output expected be implemented within the next iteration (see nodedef + * )*/ + return get_output_default(socket_out_->name, NodeItem::Type::Any); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_vertex_color_cc void register_node_type_sh_vertex_color() @@ -82,6 +92,7 @@ void register_node_type_sh_vertex_color() node_type_storage( &ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_vertex_color; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc index 221beb777f0..de80829b3fe 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc +++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc @@ -40,6 +40,15 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat, } } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: This node doesn't have an implementation in MaterialX.*/ + return get_output_default(socket_out_->name, NodeItem::Type::Float); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_wireframe_cc /* node type definition */ @@ -53,6 +62,7 @@ void register_node_type_sh_wireframe() ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_shader_buts_wireframe; ntype.gpu_fn = file_ns::node_shader_gpu_wireframe; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From f6e00155f9a98a06e9bbf695709da8609d5aaa2c Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Fri, 15 Sep 2023 20:10:51 +0200 Subject: [PATCH 23/40] MaterialX: Implement more shader nodes ### Purpose Implement more shader nodes ### Technical steps Added type: `NodeItem::Type::multioutput` Added nodes: * Glossy BSDF * Glass BSDF * Refraction BSDF Pull Request: https://projects.blender.org/DagerD/blender/pulls/23 --- .../nodes/shader/materialx/node_item.cc | 5 ++ .../nodes/shader/materialx/node_item.h | 2 +- .../shader/nodes/node_shader_bsdf_glass.cc | 46 +++++++++++++++++++ .../shader/nodes/node_shader_bsdf_glossy.cc | 36 +++++++++++++++ .../nodes/node_shader_bsdf_refraction.cc | 27 +++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index af3d6af54f6..ddade2e7704 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -13,6 +13,9 @@ NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} NodeItem::Type NodeItem::type(const std::string &type_str) { + if (type_str == "multioutput") { + return Type::Multioutput; + } if (type_str == "string") { return Type::String; } @@ -64,6 +67,8 @@ std::string NodeItem::type(Type type) switch (type) { case Type::Any: return ""; + case Type::Multioutput: + return "multioutput"; case Type::String: return "string"; case Type::Filename: diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index 704e70832a4..d35824f5c64 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -16,7 +16,7 @@ class NodeItem { enum class Type { Any = 0, Empty, - + Multioutput, /* Value types */ String, Filename, diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index 02b721e2920..5469569339b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -42,6 +42,51 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_glass", in, out, GPU_constant(&use_multi_scatter)); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Vector2); + NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem dielectric = create_node("dielectric_bsdf", NodeItem::Type::BSDF); + if (normal) { + dielectric.set_input("normal", normal); + } + dielectric.set_input("tint", color); + dielectric.set_input("roughness", roughness); + dielectric.set_input("ior", ior); + dielectric.set_input("scatter_mode", val(std::string("RT"))); + + NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); + artistic_ior.add_output("ior", NodeItem::Type::Color3); + artistic_ior.add_output("extinction", NodeItem::Type::Color3); + artistic_ior.set_input("reflectivity", color); + artistic_ior.set_input("edge_color", color); + + NodeItem conductor = create_node("conductor_bsdf", NodeItem::Type::BSDF); + if (normal) { + conductor.set_input("normal", normal); + } + conductor.set_input_output("ior", artistic_ior, "ior"); + conductor.set_input_output("extinction", artistic_ior, "extinction"); + conductor.set_input("roughness", roughness); + + NodeItem res = create_node("mix", NodeItem::Type::BSDF); + res.set_input("fg", dielectric); + res.set_input("bg", conductor); + res.set_input("mix", val(0.5f)); + + return res ; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_glass_cc /* node type definition */ @@ -57,6 +102,7 @@ void register_node_type_sh_bsdf_glass() blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.initfunc = file_ns::node_shader_init_glass; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_glass; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index 44e6887233b..60956f9f0a2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -56,6 +56,41 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_constant(&use_multi_scatter)); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Vector2); + NodeItem anisotropy = get_input_value("Anisotropy", NodeItem::Type::Color3); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); + + NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); + artistic_ior.add_output("ior", NodeItem::Type::Color3); + artistic_ior.add_output("extinction", NodeItem::Type::Color3); + artistic_ior.set_input("reflectivity", color); + artistic_ior.set_input("edge_color", color); + + NodeItem res = create_node("conductor_bsdf", NodeItem::Type::BSDF); + if (normal) { + res.set_input("normal", normal); + } + if (tangent) { + res.set_input("tangent", tangent); + } + res.set_input_output("ior", artistic_ior, "ior"); + res.set_input_output("extinction", artistic_ior, "extinction"); + res.set_input("roughness", roughness); + + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_glossy_cc /* node type definition */ @@ -72,6 +107,7 @@ void register_node_type_sh_bsdf_glossy() blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.initfunc = file_ns::node_shader_init_glossy; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_glossy; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index 4e0de9a0517..c3427ec9138 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -40,6 +40,32 @@ static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + if (to_type_ != NodeItem::Type::BSDF) { + return empty(); + } + + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Vector2); + NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + NodeItem res = create_node("dielectric_bsdf", NodeItem::Type::BSDF); + if (normal) { + res.set_input("normal", normal); + } + res.set_input("tint", color); + res.set_input("roughness", roughness); + res.set_input("ior", ior); + res.set_input("scatter_mode", val(std::string("T"))); + + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_refraction_cc /* node type definition */ @@ -55,6 +81,7 @@ void register_node_type_sh_bsdf_refraction() blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); ntype.initfunc = file_ns::node_shader_init_refraction; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_refraction; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From 412b40266fd081e8fcb509022e18576e2427701f Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Mon, 18 Sep 2023 12:48:56 +0200 Subject: [PATCH 24/40] Support group nodes ### Purpose Group nodes should be supported. ### Technical steps 1. Created classes `GroupNodeParser`, `GroupOutputNodeParser`, `GroupInputNodeParser` in `materialx/group_nodes.cc/.h`. 2. Added support of `NodeItem::input`, `NodeItem::output`. 3. Added control to use `` by `#define USE_MATERIALX_NODEGRAPH`. Disabled by default because `pxr::UsdMtlxRead()` doesn't perform nodegraphs. 4. Added logging of `stage->ExportToString()` after `pxr::UsdMtlxRead()`. 5. Improvement in `node_shader_tex_noise.cc`. Pull Request: https://projects.blender.org/DagerD/blender/pulls/22 --- source/blender/io/usd/hydra/material.cc | 10 ++ source/blender/nodes/shader/CMakeLists.txt | 2 + .../nodes/shader/materialx/group_nodes.cc | 151 ++++++++++++++++++ .../nodes/shader/materialx/group_nodes.h | 41 +++++ .../nodes/shader/materialx/material.cc | 6 +- .../nodes/shader/materialx/node_item.cc | 81 +++++++--- .../nodes/shader/materialx/node_item.h | 15 +- .../nodes/shader/materialx/node_parser.cc | 49 +++++- .../nodes/shader/materialx/node_parser.h | 14 +- .../shader/nodes/node_shader_bsdf_glass.cc | 10 +- .../shader/nodes/node_shader_bsdf_glossy.cc | 8 +- .../nodes/node_shader_bsdf_refraction.cc | 2 +- .../shader/nodes/node_shader_tex_noise.cc | 6 +- 13 files changed, 345 insertions(+), 50 deletions(-) create mode 100644 source/blender/nodes/shader/materialx/group_nodes.cc create mode 100644 source/blender/nodes/shader/materialx/group_nodes.h diff --git a/source/blender/io/usd/hydra/material.cc b/source/blender/io/usd/hydra/material.cc index a992dbdbfa3..9fdf47965a8 100644 --- a/source/blender/io/usd/hydra/material.cc +++ b/source/blender/io/usd/hydra/material.cc @@ -81,6 +81,16 @@ void MaterialData::init() MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx( scene_delegate_->depsgraph, (Material *)id); pxr::UsdMtlxRead(doc, stage); + + /* Logging stage: creating lambda stage_str() for not to call stage->ExportToString() + * if log won't be printed. */ + auto stage_str = [&stage]() { + std::string str; + stage->ExportToString(&str); + return str; + }; + ID_LOGN(2, "Stage:\n%s", stage_str().c_str()); + if (pxr::UsdPrim materials = stage->GetPrimAtPath(pxr::SdfPath("/MaterialX/Materials"))) { pxr::UsdPrimSiblingRange children = materials.GetChildren(); if (!children.empty()) { diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 25990bdcd1a..f437420e5d4 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -150,10 +150,12 @@ if(WITH_MATERIALX) materialx/material.cc materialx/node_item.cc materialx/node_parser.cc + materialx/group_nodes.cc materialx/material.h materialx/node_item.h materialx/node_parser.h + materialx/group_nodes.h ) list(APPEND LIB MaterialXCore diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc new file mode 100644 index 00000000000..f2de9e68b4d --- /dev/null +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -0,0 +1,151 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "group_nodes.h" +#include "node_parser.h" + +#include "BLI_vector.hh" + +namespace blender::nodes::materialx { + +NodeItem GroupNodeParser::compute() +{ + NodeItem res = empty(); + + const bNodeTree *ngroup = reinterpret_cast(node_->id); + ngroup->ensure_topology_cache(); + const bNode *node_out = ngroup->group_output_node(); + if (!node_out) { + return res; + } + + MaterialX::GraphElement *graph = graph_; +#ifdef USE_MATERIALX_NODEGRAPH + std::string name = MaterialX::createValidName(ngroup->id.name); + MaterialX::NodeGraphPtr group_graph = graph_->getChildOfType(name); + if (!group_graph) { + CLOG_INFO(LOG_MATERIALX_SHADER, 1, "", name.c_str()); + group_graph = graph_->addChild(name); + } + graph = group_graph.get(); +#endif + + NodeItem out = + GroupOutputNodeParser( + graph, depsgraph_, material_, node_out, socket_out_, NodeItem::Type::Any, this) + .compute_full(); + +#ifdef USE_MATERIALX_NODEGRAPH + /* We have to be in NodeParser's graph_, therefore copying output */ + res.output = out.output; +#else + res = out; +#endif + return res; +} + +NodeItem GroupNodeParser::compute_full() +{ + NodeItem res = compute(); + if (NodeItem::is_arithmetic(to_type_)) { + res = res.convert(to_type_); + } + return res; +} + +NodeItem GroupOutputNodeParser::compute() +{ +#ifdef USE_MATERIALX_NODEGRAPH + Vector values; + for (auto socket_in : node_->input_sockets()) { + NodeItem value = get_input_value(socket_in->index(), NodeItem::Type::Any); + if (value.value) { + NodeItem constant = create_node("constant", value.type()); + constant.set_input("value", value); + value = constant; + } + values.append(value); + } + Vector outputs; + for (int i = 0; i < values.size(); ++i) { + if (values[i]) { + outputs.append(create_output("output" + std::to_string(i + 1), values[i])); + } + } + return outputs[socket_out_->index()]; +#else + return get_input_value(socket_out_->index(), NodeItem::Type::Any); +#endif +} + +NodeItem GroupOutputNodeParser::compute_full() +{ +#ifdef USE_MATERIALX_NODEGRAPH + NodeItem res = empty(); + + /* Checking if output was already computed */ + res.output = graph_->getOutput("output" + std::to_string(socket_out_->index() + 1)); + if (res.output) { + return res; + } + + CLOG_INFO(LOG_MATERIALX_SHADER, + 1, + "%s [%d] => %s", + node_->name, + node_->typeinfo->type, + NodeItem::type(to_type_).c_str()); + + res = compute(); + return res; +#else + return NodeParser::compute_full(); +#endif +} + +NodeItem GroupInputNodeParser::compute() +{ +#ifdef USE_MATERIALX_NODEGRAPH + NodeItem value = group_parser_->get_input_link(socket_out_->index(), to_type_); + if (!value) { + return empty(); + } + + if (value.value) { + NodeItem constant = create_node("constant", value.type()); + constant.set_input("value", value); + value = constant; + } + return create_input("input" + std::to_string(socket_out_->index() + 1), value); +#else + return group_parser_->get_input_link(socket_out_->index(), to_type_); +#endif +} + +NodeItem GroupInputNodeParser::compute_full() +{ +#ifdef USE_MATERIALX_NODEGRAPH + NodeItem res = empty(); + + /* Checking if output was already computed */ + res.input = graph_->getInput("input" + std::to_string(socket_out_->index() + 1)); + if (res.input) { + return res; + } + + CLOG_INFO(LOG_MATERIALX_SHADER, + 1, + "%s [%d] => %s", + node_->name, + node_->typeinfo->type, + NodeItem::type(to_type_).c_str()); + + res = compute(); + return res; +#else + return NodeParser::compute_full(); +#endif +} + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/group_nodes.h b/source/blender/nodes/shader/materialx/group_nodes.h new file mode 100644 index 00000000000..a486a4af5fd --- /dev/null +++ b/source/blender/nodes/shader/materialx/group_nodes.h @@ -0,0 +1,41 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "node_parser.h" + +/* TODO: pxr::UsdMtlxRead() doesn't perform nodegraphs. + * Uncomment USE_MATERIALX_NODEGRAPH after fixing it. */ +//#define USE_MATERIALX_NODEGRAPH + +namespace blender::nodes::materialx { + +class GroupInputNodeParser; + +class GroupNodeParser : public NodeParser { + friend NodeParser; + friend GroupInputNodeParser; + + public: + using NodeParser::NodeParser; + NodeItem compute() override; + NodeItem compute_full() override; +}; + +class GroupOutputNodeParser : public NodeParser { + public: + using NodeParser::NodeParser; + NodeItem compute() override; + NodeItem compute_full() override; +}; + +class GroupInputNodeParser : public NodeParser { + public: + using NodeParser::NodeParser; + NodeItem compute() override; + NodeItem compute_full() override; +}; + +} // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 540204a8d87..9e40a51489b 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -62,18 +62,18 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); if (output_node) { NodeParserData data = { - doc.get(), depsgraph, material, NodeItem::Type::Material, NodeItem(doc.get())}; + doc.get(), depsgraph, material, NodeItem::Type::Material, nullptr, NodeItem(doc.get())}; output_node->typeinfo->materialx_fn(&data, output_node, nullptr); } else { DefaultMaterialNodeParser( - doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material) + doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material, nullptr) .compute_error(); } } else { DefaultMaterialNodeParser( - doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material) + doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material, nullptr) .compute(); } diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index ddade2e7704..f431a711ce3 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -66,7 +66,7 @@ std::string NodeItem::type(Type type) { switch (type) { case Type::Any: - return ""; + return "any"; case Type::Multioutput: return "multioutput"; case Type::String: @@ -103,9 +103,14 @@ std::string NodeItem::type(Type type) return ""; } +bool NodeItem::is_arithmetic(Type type) +{ + return type >= Type::Float && type <= Type::Color4; +} + NodeItem::operator bool() const { - return value || node; + return value || node || input || output; } NodeItem NodeItem::operator+(const NodeItem &other) const @@ -604,8 +609,8 @@ NodeItem NodeItem::if_else(CompareOp op, NodeItem NodeItem::extract(const int index) const { - NodeItem res = empty(); - res = create_node("extract", Type::Float); + /* TODO: Add check if (value) { ... } */ + NodeItem res = create_node("extract", Type::Float); res.set_input("in", *this); res.set_input("index", val(index)); return res; @@ -624,6 +629,9 @@ NodeItem::Type NodeItem::type() const if (node) { return type(node->getType()); } + if (output) { + return type(output->getType()); + } return Type::Empty; } @@ -675,30 +683,59 @@ void NodeItem::set_input(const std::string &in_name, const NodeItem &item) else if (item.node) { node->setConnectedNode(in_name, item.node); } + else if (item.input) { + node->setAttribute("interfacename", item.input->getName()); + } + else if (item.output) { + node->setConnectedOutput(in_name, item.output); + } else { CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", in_name.c_str()); } } -void NodeItem::set_input_output(const std::string &in_name, - const NodeItem &item, - const std::string &out_name) +NodeItem NodeItem::add_output(const std::string &out_name, Type out_type) { - if (!item.node) { + NodeItem res = empty(); + res.output = node->addOutput(out_name, type(out_type)); + return res; +} + +NodeItem NodeItem::create_input(const std::string &name, const NodeItem &item) const +{ + NodeItem res = empty(); + res.input = graph_->addInput(name); + + Type item_type = item.type(); + if (item.node) { + res.input->setConnectedNode(item.node); + } + else { BLI_assert_unreachable(); } - node->setConnectedNode(in_name, item.node); - node->setConnectedOutput(in_name, item.node->getOutput(out_name)); + res.input->setType(type(item_type)); + + return res; } -void NodeItem::add_output(const std::string &name, Type out_type) +NodeItem NodeItem::create_output(const std::string &name, const NodeItem &item) const { - node->addOutput(name, type(out_type)); -} + NodeItem res = empty(); + res.output = graph_->addOutput(name); -bool NodeItem::is_arithmetic(Type type) -{ - return type >= Type::Float && type <= Type::Color4; + Type item_type = item.type(); + if (item.node) { + res.output->setConnectedNode(item.node); + } + else if (item.input) { + res.output->setInterfaceName(item.input->getName()); + } + else { + BLI_assert_unreachable(); + } + res.output->setType(type(item_type)); + + return res; } NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2) @@ -776,10 +813,16 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function NodeItem val(const T &data) const; Type type() const; - NodeItem create_node(const std::string &category, NodeItem::Type type) const; - /* Functions to set input and output */ + /* Node functions */ + NodeItem create_node(const std::string &category, NodeItem::Type type) const; template void set_input(const std::string &in_name, const T &value, Type in_type); void set_input(const std::string &in_name, const NodeItem &item); - void set_input_output(const std::string &in_name, - const NodeItem &item, - const std::string &out_name); - void add_output(const std::string &in_name, Type out_type); + NodeItem add_output(const std::string &out_name, Type out_type); + + /* Output functions */ + NodeItem create_input(const std::string &name, const NodeItem &item) const; + NodeItem create_output(const std::string &name, const NodeItem &item) const; private: static Type cast_types(NodeItem &item1, NodeItem &item2); diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index 297d39aec01..73303ec03fe 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -4,6 +4,8 @@ #include "node_parser.h" +#include "group_nodes.h" + #include "BKE_node_runtime.hh" namespace blender::nodes::materialx { @@ -17,13 +19,15 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph, const Material *material, const bNode *node, const bNodeSocket *socket_out, - NodeItem::Type to_type) + NodeItem::Type to_type, + GroupNodeParser *group_parser) : graph_(graph), depsgraph_(depsgraph), material_(material), node_(node), socket_out_(socket_out), - to_type_(to_type) + to_type_(to_type), + group_parser_(group_parser) { } @@ -52,7 +56,7 @@ NodeItem NodeParser::compute_full() return res; } -std::string NodeParser::node_name() +std::string NodeParser::node_name() const { std::string name = node_->name; if (node_->output_sockets().size() > 1) { @@ -61,7 +65,18 @@ std::string NodeParser::node_name() if (ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { name += "_" + NodeItem::type(to_type_); } +#ifdef USE_MATERIALX_NODEGRAPH return MaterialX::createValidName(name); +#else + std::string prefix; + GroupNodeParser *gr = group_parser_; + while (gr) { + const bNodeTree *ngroup = reinterpret_cast(gr->node_->id); + prefix = MaterialX::createValidName(ngroup->id.name) + "_" + prefix; + gr = gr->group_parser_; + } + return prefix + MaterialX::createValidName(name); +#endif } NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type) @@ -69,6 +84,16 @@ NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type typ return empty().create_node(category, type); } +NodeItem NodeParser::create_input(const std::string &name, const NodeItem &item) +{ + return empty().create_input(name, item); +} + +NodeItem NodeParser::create_output(const std::string &name, const NodeItem &item) +{ + return empty().create_output(name, item); +} + NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type) { return get_default(node_->input_by_identifier(name), to_type); @@ -129,6 +154,9 @@ NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_ty { NodeItem res = empty(); switch (socket.type) { + case SOCK_CUSTOM: + /* Return empty */ + break; case SOCK_FLOAT: { float v = socket.default_value_typed()->value; res.value = MaterialX::Value::createValue(v); @@ -163,7 +191,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to const bNode *from_node = link->fromnode; /* Passing NODE_REROUTE nodes */ - while (from_node->type == NODE_REROUTE) { + while (from_node->is_reroute()) { link = from_node->input_socket(0).link; if (!(link && link->is_used())) { return empty(); @@ -171,6 +199,17 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to from_node = link->fromnode; } + if (from_node->is_group()) { + return GroupNodeParser( + graph_, depsgraph_, material_, from_node, link->fromsock, to_type, group_parser_) + .compute_full(); + } + if (from_node->is_group_input()) { + return GroupInputNodeParser( + graph_, depsgraph_, material_, from_node, link->fromsock, to_type, group_parser_) + .compute_full(); + } + if (!from_node->typeinfo->materialx_fn) { CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported node: %s [%d]", @@ -179,7 +218,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to return empty(); } - NodeParserData data = {graph_, depsgraph_, material_, to_type, empty()}; + NodeParserData data = {graph_, depsgraph_, material_, to_type, group_parser_, empty()}; from_node->typeinfo->materialx_fn(&data, const_cast(from_node), link->fromsock); return data.result; } diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index 464c92c0e64..208b44320b1 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -16,6 +16,8 @@ namespace blender::nodes::materialx { extern struct CLG_LogRef *LOG_MATERIALX_SHADER; +class GroupNodeParser; + class NodeParser { protected: MaterialX::GraphElement *graph_; @@ -24,6 +26,7 @@ class NodeParser { const bNode *node_; const bNodeSocket *socket_out_; NodeItem::Type to_type_; + GroupNodeParser *group_parser_; public: NodeParser(MaterialX::GraphElement *graph, @@ -31,15 +34,18 @@ class NodeParser { const Material *material, const bNode *node, const bNodeSocket *socket_out, - NodeItem::Type to_type); + NodeItem::Type to_type, + GroupNodeParser *group_parser); virtual ~NodeParser() = default; virtual NodeItem compute() = 0; virtual NodeItem compute_full(); protected: - std::string node_name(); + std::string node_name() const; NodeItem create_node(const std::string &category, NodeItem::Type type); + NodeItem create_input(const std::string &name, const NodeItem &item); + NodeItem create_output(const std::string &name, const NodeItem &item); NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); NodeItem get_input_default(int index, NodeItem::Type to_type); NodeItem get_output_default(const std::string &name, NodeItem::Type to_type); @@ -71,6 +77,7 @@ struct NodeParserData { const Depsgraph *depsgraph; const Material *material; NodeItem::Type to_type; + GroupNodeParser *group_parser; NodeItem result; }; @@ -91,7 +98,8 @@ struct NodeParserData { void node_shader_materialx(void *data, struct bNode *node, struct bNodeSocket *out) \ { \ materialx::NodeParserData *d = reinterpret_cast(data); \ - d->result = MaterialXNodeParser(d->graph, d->depsgraph, d->material, node, out, d->to_type) \ + d->result = MaterialXNodeParser( \ + d->graph, d->depsgraph, d->material, node, out, d->to_type, d->group_parser) \ .compute_full(); \ } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index 5469569339b..d4467eb5765 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -64,17 +64,17 @@ NODE_SHADER_MATERIALX_BEGIN dielectric.set_input("scatter_mode", val(std::string("RT"))); NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); - artistic_ior.add_output("ior", NodeItem::Type::Color3); - artistic_ior.add_output("extinction", NodeItem::Type::Color3); artistic_ior.set_input("reflectivity", color); artistic_ior.set_input("edge_color", color); + NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3); + NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3); NodeItem conductor = create_node("conductor_bsdf", NodeItem::Type::BSDF); if (normal) { conductor.set_input("normal", normal); } - conductor.set_input_output("ior", artistic_ior, "ior"); - conductor.set_input_output("extinction", artistic_ior, "extinction"); + conductor.set_input("ior", ior_out); + conductor.set_input("extinction", extinction_out); conductor.set_input("roughness", roughness); NodeItem res = create_node("mix", NodeItem::Type::BSDF); @@ -82,7 +82,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("bg", conductor); res.set_input("mix", val(0.5f)); - return res ; + return res; } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index 60956f9f0a2..b340b8e62a4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -70,10 +70,10 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); - artistic_ior.add_output("ior", NodeItem::Type::Color3); - artistic_ior.add_output("extinction", NodeItem::Type::Color3); artistic_ior.set_input("reflectivity", color); artistic_ior.set_input("edge_color", color); + NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3); + NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3); NodeItem res = create_node("conductor_bsdf", NodeItem::Type::BSDF); if (normal) { @@ -82,8 +82,8 @@ NODE_SHADER_MATERIALX_BEGIN if (tangent) { res.set_input("tangent", tangent); } - res.set_input_output("ior", artistic_ior, "ior"); - res.set_input_output("extinction", artistic_ior, "extinction"); + res.set_input("ior", ior_out); + res.set_input("extinction", extinction_out); res.set_input("roughness", roughness); return res; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index c3427ec9138..dfaf30c5e98 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -60,7 +60,7 @@ NODE_SHADER_MATERIALX_BEGIN res.set_input("roughness", roughness); res.set_input("ior", ior); res.set_input("scatter_mode", val(std::string("T"))); - + return res; } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index 8fe27900be4..faa16e50cf8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -261,7 +261,7 @@ NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); - NodeItem detail = get_input_value("Detail", NodeItem::Type::Float); + NodeItem detail = get_input_default("Detail", NodeItem::Type::Float); NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); NodeItem position = create_node("position", NodeItem::Type::Vector3); @@ -269,9 +269,7 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem res = create_node("fractal3d", NodeItem::Type::Color3); res.set_input("position", position); - if (detail.value) { - res.set_input("octaves", val(int(detail.value->asA()))); - } + res.set_input("octaves", val(int(detail.value->asA()))); res.set_input("lacunarity", lacunarity); return res; } -- 2.30.2 From 1bafc3518a7f8729306734a76b0b038d536e1dce Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 19 Sep 2023 18:12:33 +0200 Subject: [PATCH 25/40] Fix creating 2 nodes in TexImage when Color and Output are connected ### Purpose TexImage node creates 2 nodes when Color and Output are connected. ### Technical steps Added name to node, same as node_name with Color output. Added implementation of TexEnvironment node. Fixed naming in group_nodes.cc Pull Request: https://projects.blender.org/DagerD/blender/pulls/24 --- .../nodes/shader/materialx/group_nodes.cc | 4 +- .../nodes/node_shader_tex_environment.cc | 50 +++++++- .../shader/nodes/node_shader_tex_image.cc | 116 ++++++++++-------- 3 files changed, 112 insertions(+), 58 deletions(-) diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc index f2de9e68b4d..32bed65aff9 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.cc +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -100,7 +100,7 @@ NodeItem GroupOutputNodeParser::compute_full() res = compute(); return res; #else - return NodeParser::compute_full(); + return compute(); #endif } @@ -144,7 +144,7 @@ NodeItem GroupInputNodeParser::compute_full() res = compute(); return res; #else - return NodeParser::compute_full(); + return compute(); #endif } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index cc828b8bdf4..30ad01b489f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -11,6 +11,10 @@ #include "IMB_colormanagement.h" +#include "hydra/image.h" + +#include "DEG_depsgraph_query.h" + namespace blender::nodes::node_shader_tex_environment_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -130,8 +134,50 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* TODO: Implement */ - return empty(); + NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); + + Image *image = (Image *)node_->id; + if (!image) { + return res; + } + + NodeTexEnvironment *tex_env = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); + + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains + * pretty general code, so could be moved from bf_usd project. */ + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_env->iuser); + + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: texcoords should be translated to spherical coordinates */ + + std::string filtertype; + switch (tex_env->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); + res.set_input("file", image_path, NodeItem::Type::Filename); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + + return res; } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index c683db52e4a..90963a99127 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -179,64 +179,72 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); + /* Getting node name for Color output. This name will be used for node. */ + std::string image_node_name = node_name(); + image_node_name = image_node_name.substr(0, image_node_name.rfind('_')) + "_Color"; - Image *image = (Image *)node_->id; - if (image) { - NodeTexImage *tex_image = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); + NodeItem res = empty(); + res.node = graph_->getNode(image_node_name); + if (!res.node) { + res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains - * pretty general code, so could be moved from bf_usd project. */ - std::string image_path = io::hydra::cache_or_get_image_file( - bmain, scene, image, &tex_image->iuser); + Image *image = (Image *)node_->id; + if (image) { + NodeTexImage *tex_image = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); - NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); - if (!vector) { - vector = texcoord_node(); + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file + * contains pretty general code, so could be moved from bf_usd project. */ + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_image->iuser); + + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: add math to vector depending of tex_image->projection */ + + std::string filtertype; + switch (tex_image->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + std::string addressmode; + switch (tex_image->extension) { + case SHD_IMAGE_EXTENSION_REPEAT: + addressmode = "periodic"; + break; + case SHD_IMAGE_EXTENSION_EXTEND: + addressmode = "clamp"; + break; + case SHD_IMAGE_EXTENSION_CLIP: + addressmode = "constant"; + break; + case SHD_IMAGE_EXTENSION_MIRROR: + addressmode = "mirror"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); + res.set_input("file", image_path, NodeItem::Type::Filename); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + res.set_input("uaddressmode", val(addressmode)); + res.set_input("vaddressmode", val(addressmode)); } - /* TODO: add math to vector depending of tex_image->projection */ - - std::string filtertype; - switch (tex_image->interpolation) { - case SHD_INTERP_LINEAR: - filtertype = "linear"; - break; - case SHD_INTERP_CLOSEST: - filtertype = "closest"; - break; - case SHD_INTERP_CUBIC: - case SHD_INTERP_SMART: - filtertype = "cubic"; - break; - default: - BLI_assert_unreachable(); - } - std::string addressmode; - switch (tex_image->extension) { - case SHD_IMAGE_EXTENSION_REPEAT: - addressmode = "periodic"; - break; - case SHD_IMAGE_EXTENSION_EXTEND: - addressmode = "clamp"; - break; - case SHD_IMAGE_EXTENSION_CLIP: - addressmode = "constant"; - break; - case SHD_IMAGE_EXTENSION_MIRROR: - addressmode = "mirror"; - break; - default: - BLI_assert_unreachable(); - } - - res = create_node("image", NodeItem::Type::Color4); - res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", vector); - res.set_input("filtertype", val(filtertype)); - res.set_input("uaddressmode", val(addressmode)); - res.set_input("vaddressmode", val(addressmode)); } if (STREQ(socket_out_->name, "Alpha")) { -- 2.30.2 From 2f980a98569520e35b580d9beec84eb45a7697f2 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 19 Sep 2023 18:27:49 +0200 Subject: [PATCH 26/40] matx-extend-create_node ### Purpose Add parameter `inputs` to `NodeItem::create_node()` and simplify node creation in export implementation. ### Technical steps Added type `NodeItem::Inputs` Added parameter `inputs` to `NodeItem::create_node()`. Updated node export implementation with new functionality. Pull Request: https://projects.blender.org/DagerD/blender/pulls/25 --- .../nodes/shader/materialx/group_nodes.cc | 8 +- .../nodes/shader/materialx/material.cc | 24 +++--- .../nodes/shader/materialx/node_item.cc | 43 +++++----- .../nodes/shader/materialx/node_item.h | 7 +- .../nodes/shader/materialx/node_parser.cc | 7 ++ .../nodes/shader/materialx/node_parser.h | 3 + .../shader/nodes/node_shader_bsdf_diffuse.cc | 10 +-- .../shader/nodes/node_shader_bsdf_glass.cc | 42 +++++----- .../shader/nodes/node_shader_bsdf_glossy.cc | 25 +++--- .../nodes/node_shader_bsdf_principled.cc | 79 ++++++++----------- .../nodes/node_shader_bsdf_refraction.cc | 17 ++-- .../shader/nodes/node_shader_bsdf_sheen.cc | 12 +-- .../nodes/node_shader_bsdf_translucent.cc | 8 +- .../shader/nodes/node_shader_emission.cc | 4 +- .../shader/nodes/node_shader_geometry.cc | 9 +-- .../shader/nodes/node_shader_hueSatVal.cc | 11 +-- .../nodes/shader/nodes/node_shader_invert.cc | 2 +- .../shader/nodes/node_shader_map_range.cc | 16 ++-- .../shader/nodes/node_shader_mix_shader.cc | 5 +- .../shader/nodes/node_shader_normal_map.cc | 8 +- .../shader/nodes/node_shader_object_info.cc | 3 +- .../nodes/node_shader_output_material.cc | 4 +- .../nodes/shader/nodes/node_shader_rgb.cc | 4 +- .../shader/nodes/node_shader_rgb_to_bw.cc | 5 +- .../shader/nodes/node_shader_sepcomb_color.cc | 3 +- .../shader/nodes/node_shader_sepcomb_xyz.cc | 6 +- .../node_shader_subsurface_scattering.cc | 16 ++-- .../shader/nodes/node_shader_tex_coord.cc | 6 +- .../shader/nodes/node_shader_tex_image.cc | 12 +-- .../shader/nodes/node_shader_tex_noise.cc | 10 +-- .../nodes/shader/nodes/node_shader_value.cc | 4 +- 31 files changed, 177 insertions(+), 236 deletions(-) diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc index 32bed65aff9..7f13fb108ae 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.cc +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -61,9 +61,7 @@ NodeItem GroupOutputNodeParser::compute() for (auto socket_in : node_->input_sockets()) { NodeItem value = get_input_value(socket_in->index(), NodeItem::Type::Any); if (value.value) { - NodeItem constant = create_node("constant", value.type()); - constant.set_input("value", value); - value = constant; + value = create_node("constant", value.type(), {{"value", value}}); } values.append(value); } @@ -113,9 +111,7 @@ NodeItem GroupInputNodeParser::compute() } if (value.value) { - NodeItem constant = create_node("constant", value.type()); - constant.set_input("value", value); - value = constant; + value = create_node("constant", value.type(), {{"value", value}}); } return create_input("input" + std::to_string(socket_out_->index() + 1), value); #else diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 9e40a51489b..4da740b5431 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -21,10 +21,12 @@ class DefaultMaterialNodeParser : public NodeParser { NodeItem compute() override { - NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); - surface.set_input("base_color", - val(MaterialX::Color3(material_->r, material_->g, material_->b))); - surface.set_input("diffuse_roughness", val(material_->roughness)); + NodeItem surface = create_node( + "standard_surface", + NodeItem::Type::SurfaceShader, + {{"base_color", val(MaterialX::Color3(material_->r, material_->g, material_->b))}, + {"diffuse_roughness", val(material_->roughness)}}); + if (material_->metallic > 0.0f) { surface.set_input("metalness", val(material_->metallic)); } @@ -34,20 +36,20 @@ class DefaultMaterialNodeParser : public NodeParser { surface.set_input("specular_roughness", val(material_->roughness)); } - NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); + NodeItem res = create_node( + "surfacematerial", NodeItem::Type::Material, {{"surfaceshader", surface}}); res.node->setName("Material_Default"); - res.set_input("surfaceshader", surface); return res; } NodeItem compute_error() { - NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader); - surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f))); - - NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); + NodeItem surface = create_node("standard_surface", + NodeItem::Type::SurfaceShader, + {{"base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f))}}); + NodeItem res = create_node( + "surfacematerial", NodeItem::Type::Material, {{"surfaceshader", surface}}); res.node->setName("Material_Error"); - res.set_input("surfaceshader", surface); return res; } }; diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index f431a711ce3..8fa84213de7 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "node_item.h" +#include "node_parser.h" #include "BLI_assert.h" #include "BLI_utildefines.h" @@ -120,9 +121,7 @@ NodeItem NodeItem::operator+(const NodeItem &other) const /* Special case: add BSDF/EDF shaders */ NodeItem res = empty(); if (other.type() == type) { - res = create_node("add", type); - res.set_input("in1", *this); - res.set_input("in2", other); + res = create_node("add", type, {{"in1", *this}, {"in2", other}}); } else { BLI_assert_unreachable(); @@ -151,9 +150,7 @@ NodeItem NodeItem::operator*(const NodeItem &other) const NodeItem res = empty(); Type other_type = other.type(); if (ELEM(other_type, Type::Float, Type::Color3)) { - res = create_node("multiply", type); - res.set_input("in1", *this); - res.set_input("in2", other); + res = create_node("multiply", type, {{"in1", *this}, {"in2", other}}); } else { BLI_assert_unreachable(); @@ -540,8 +537,7 @@ NodeItem NodeItem::convert(Type to_type) const } } else { - res = create_node("convert", to_type); - res.set_input("in", *this); + res = create_node("convert", to_type, {{"in", *this}}); } return res; } @@ -597,11 +593,8 @@ NodeItem NodeItem::if_else(CompareOp op, res = func(value->asA(), other.value->asA()) ? item1 : item2; } else { - res = create_node(category, to_type); - res.set_input("value1", *this); - res.set_input("value2", other); - res.set_input("in1", item1); - res.set_input("in2", item2); + res = create_node( + category, to_type, {{"value1", *this}, {"value2", other}, {"in1", item1}, {"in2", item2}}); } return res; @@ -610,9 +603,7 @@ NodeItem NodeItem::if_else(CompareOp op, NodeItem NodeItem::extract(const int index) const { /* TODO: Add check if (value) { ... } */ - NodeItem res = create_node("extract", Type::Float); - res.set_input("in", *this); - res.set_input("index", val(index)); + NodeItem res = create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}}); return res; } @@ -635,7 +626,7 @@ NodeItem::Type NodeItem::type() const return Type::Empty; } -NodeItem NodeItem::create_node(const std::string &category, NodeItem::Type type) const +NodeItem NodeItem::create_node(const std::string &category, Type type) const { std::string type_str = this->type(type); CLOG_INFO(LOG_MATERIALX_SHADER, 2, "<%s type=%s>", category.c_str(), type_str.c_str()); @@ -644,6 +635,17 @@ NodeItem NodeItem::create_node(const std::string &category, NodeItem::Type type) return res; } +NodeItem NodeItem::create_node(const std::string &category, Type type, const Inputs &inputs) const +{ + NodeItem res = create_node(category, type); + for (auto &it : inputs) { + if (it.second) { + res.set_input(it.first, it.second); + } + } + return res; +} + void NodeItem::set_input(const std::string &in_name, const NodeItem &item) { if (item.value) { @@ -821,8 +823,7 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function + #include namespace blender::nodes::materialx { @@ -13,6 +15,8 @@ namespace blender::nodes::materialx { * All work should be done via this class instead of using MaterialX API directly. */ class NodeItem { public: + using Inputs = std::vector>; + enum class Type { Any = 0, Empty, @@ -106,7 +110,8 @@ class NodeItem { Type type() const; /* Node functions */ - NodeItem create_node(const std::string &category, NodeItem::Type type) const; + NodeItem create_node(const std::string &category, Type type) const; + NodeItem create_node(const std::string &category, Type type, const Inputs &inputs) const; template void set_input(const std::string &in_name, const T &value, Type in_type); void set_input(const std::string &in_name, const NodeItem &item); NodeItem add_output(const std::string &out_name, Type out_type); diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index 73303ec03fe..158a8be3351 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -84,6 +84,13 @@ NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type typ return empty().create_node(category, type); } +NodeItem NodeParser::create_node(const std::string &category, + NodeItem::Type type, + const NodeItem::Inputs &inputs) +{ + return empty().create_node(category, type, inputs); +} + NodeItem NodeParser::create_input(const std::string &name, const NodeItem &item) { return empty().create_input(name, item); diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index 208b44320b1..eaaa5c1d35b 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -44,6 +44,9 @@ class NodeParser { protected: std::string node_name() const; NodeItem create_node(const std::string &category, NodeItem::Type type); + NodeItem create_node(const std::string &category, + NodeItem::Type type, + const NodeItem::Inputs &inputs); NodeItem create_input(const std::string &name, const NodeItem &item); NodeItem create_output(const std::string &name, const NodeItem &item); NodeItem get_input_default(const std::string &name, NodeItem::Type to_type); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index 353edc5ef58..dd8b102da5e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -45,13 +45,9 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF); - res.set_input("color", color); - res.set_input("roughness", roughness); - if (normal) { - res.set_input("normal", normal); - } - return res; + return create_node("oren_nayar_diffuse_bsdf", + NodeItem::Type::BSDF, + {{"color", color}, {"roughness", roughness}, {"normal", normal}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index d4467eb5765..37b850ab253 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -54,35 +54,29 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem dielectric = create_node("dielectric_bsdf", NodeItem::Type::BSDF); - if (normal) { - dielectric.set_input("normal", normal); - } - dielectric.set_input("tint", color); - dielectric.set_input("roughness", roughness); - dielectric.set_input("ior", ior); - dielectric.set_input("scatter_mode", val(std::string("RT"))); + NodeItem dielectric = create_node("dielectric_bsdf", + NodeItem::Type::BSDF, + {{"normal", normal}, + {"tint", color}, + {"roughness", roughness}, + {"ior", ior}, + {"scatter_mode", val(std::string("RT"))}}); - NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); - artistic_ior.set_input("reflectivity", color); - artistic_ior.set_input("edge_color", color); + NodeItem artistic_ior = create_node("artistic_ior", + NodeItem::Type::Multioutput, + {{"reflectivity", color}, {"edge_color", color}}); NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3); NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3); - NodeItem conductor = create_node("conductor_bsdf", NodeItem::Type::BSDF); - if (normal) { - conductor.set_input("normal", normal); - } - conductor.set_input("ior", ior_out); - conductor.set_input("extinction", extinction_out); - conductor.set_input("roughness", roughness); + NodeItem conductor = create_node("conductor_bsdf", + NodeItem::Type::BSDF, + {{"normal", normal}, + {"ior", ior_out}, + {"extinction", extinction_out}, + {"roughness", roughness}}); - NodeItem res = create_node("mix", NodeItem::Type::BSDF); - res.set_input("fg", dielectric); - res.set_input("bg", conductor); - res.set_input("mix", val(0.5f)); - - return res; + return create_node( + "mix", NodeItem::Type::BSDF, {{"fg", dielectric}, {"bg", conductor}, {"mix", val(0.5f)}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index b340b8e62a4..2dd68055108 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -69,24 +69,19 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); - NodeItem artistic_ior = create_node("artistic_ior", NodeItem::Type::Multioutput); - artistic_ior.set_input("reflectivity", color); - artistic_ior.set_input("edge_color", color); + NodeItem artistic_ior = create_node("artistic_ior", + NodeItem::Type::Multioutput, + {{"reflectivity", color}, {"edge_color", color}}); NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3); NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3); - NodeItem res = create_node("conductor_bsdf", NodeItem::Type::BSDF); - if (normal) { - res.set_input("normal", normal); - } - if (tangent) { - res.set_input("tangent", tangent); - } - res.set_input("ior", ior_out); - res.set_input("extinction", extinction_out); - res.set_input("roughness", roughness); - - return res; + return create_node("conductor_bsdf", + NodeItem::Type::BSDF, + {{"normal", normal}, + {"tangent", tangent}, + {"ior", ior_out}, + {"extinction", extinction_out}, + {"roughness", roughness}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index d15b7cf2783..7ff70e95b30 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -331,52 +331,39 @@ NODE_SHADER_MATERIALX_BEGIN subsurface_radius = subsurface_radius * subsurface_scale; /* Creating standard_surface */ - NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader); - res.set_input("base", val(1.0f)); - res.set_input("base_color", base_color); - res.set_input("diffuse_roughness", roughness); - if (normal) { - res.set_input("normal", normal); - } - if (tangent) { - res.set_input("tangent", tangent); - } - res.set_input("metalness", metallic); - - res.set_input("specular", specular); - res.set_input("specular_color", base_color); - 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); - - res.set_input("transmission", transmission); - res.set_input("transmission_color", base_color); - res.set_input("transmission_extra_roughness", roughness); - - res.set_input("subsurface", subsurface); - res.set_input("subsurface_color", base_color); - res.set_input("subsurface_radius", subsurface_radius); - res.set_input("subsurface_anisotropy", anisotropic); - - res.set_input("sheen", sheen); - res.set_input("sheen_color", base_color); - res.set_input("sheen_roughness", roughness); - - res.set_input("coat", coat); - res.set_input("coat_color", base_color); - res.set_input("coat_roughness", coat_roughness); - res.set_input("coat_IOR", ior); - res.set_input("coat_anisotropy", anisotropic); - res.set_input("coat_rotation", anisotropic_rotation); - if (coat_normal) { - res.set_input("coat_normal", coat_normal); - } - - res.set_input("emission", emission_strength); - res.set_input("emission_color", emission); - - return res; + return create_node("standard_surface", + NodeItem::Type::SurfaceShader, + {{"base", val(1.0f)}, + {"base_color", base_color}, + {"diffuse_roughness", roughness}, + {"normal", normal}, + {"tangent", tangent}, + {"metalness", metallic}, + {"specular", specular}, + {"specular_color", base_color}, + {"specular_roughness", roughness}, + {"specular_IOR", ior}, + {"specular_anisotropy", anisotropic}, + {"specular_rotation", anisotropic_rotation}, + {"transmission", transmission}, + {"transmission_color", base_color}, + {"transmission_extra_roughness", roughness}, + {"subsurface", subsurface}, + {"subsurface_color", base_color}, + {"subsurface_radius", subsurface_radius}, + {"subsurface_anisotropy", anisotropic}, + {"sheen", sheen}, + {"sheen_color", base_color}, + {"sheen_roughness", roughness}, + {"coat", coat}, + {"coat_color", base_color}, + {"coat_roughness", coat_roughness}, + {"coat_IOR", ior}, + {"coat_anisotropy", anisotropic}, + {"coat_rotation", anisotropic_rotation}, + {"coat_normal", coat_normal}, + {"emission", emission_strength}, + {"emission_color", emission}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index dfaf30c5e98..b5143de108a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -52,16 +52,13 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem res = create_node("dielectric_bsdf", NodeItem::Type::BSDF); - if (normal) { - res.set_input("normal", normal); - } - res.set_input("tint", color); - res.set_input("roughness", roughness); - res.set_input("ior", ior); - res.set_input("scatter_mode", val(std::string("T"))); - - return res; + return create_node("dielectric_bsdf", + NodeItem::Type::BSDF, + {{"normal", normal}, + {"tint", color}, + {"roughness", roughness}, + {"ior", ior}, + {"scatter_mode", val(std::string("T"))}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc index 27bf2229129..59469c8abb3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc @@ -58,14 +58,10 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem res = create_node("sheen_bsdf", NodeItem::Type::BSDF); - res.set_input("color", color); - res.set_input("weight", roughness); - res.set_input("roughness", roughness); - if (normal) { - res.set_input("normal", normal); - } - return res; + return create_node( + "sheen_bsdf", + NodeItem::Type::BSDF, + {{"color", color}, {"weight", roughness}, {"roughness", roughness}, {"normal", normal}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index ed787b20161..add64251ace 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -39,12 +39,8 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem res = create_node("translucent_bsdf", NodeItem::Type::BSDF); - res.set_input("color", color); - if (normal) { - res.set_input("normal", normal); - } - return res; + return create_node( + "translucent_bsdf", NodeItem::Type::BSDF, {{"color", color}, {"normal", normal}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.cc b/source/blender/nodes/shader/nodes/node_shader_emission.cc index dbd56fedc40..dbdf54bf08e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_emission.cc +++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc @@ -34,9 +34,7 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem color = get_input_value("Color", NodeItem::Type::Color3); NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); - NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF); - res.set_input("color", color * strength); - return res; + return create_node("uniform_edf", NodeItem::Type::EDF, {{"color", color * strength}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.cc b/source/blender/nodes/shader/nodes/node_shader_geometry.cc index 651d6f4c390..6d916b39f7b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.cc +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc @@ -66,16 +66,13 @@ NODE_SHADER_MATERIALX_BEGIN std::string name = socket_out_->name; if (name == "Position") { - res = create_node("position", NodeItem::Type::Vector3); - res.set_input("space", val(std::string("world"))); + res = create_node("position", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } else if (name == "Normal") { - res = create_node("normal", NodeItem::Type::Vector3); - res.set_input("space", val(std::string("world"))); + res = create_node("normal", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } else if (ELEM(name, "Tangent", "True Normal")) { - res = create_node("tangent", NodeItem::Type::Vector3); - res.set_input("space", val(std::string("world"))); + res = create_node("tangent", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } else { res = get_output_default(name, NodeItem::Type::Any); diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc index 2c00df75e91..05a4d85ddd0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc +++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc @@ -43,15 +43,10 @@ NODE_SHADER_MATERIALX_BEGIN /* Modifier to follow Cycles result */ hue = hue - val(0.5f); - NodeItem combine = create_node("combine3", NodeItem::Type::Vector3); - combine.set_input("in1", hue); - combine.set_input("in2", saturation); - combine.set_input("in3", value); + NodeItem combine = create_node( + "combine3", NodeItem::Type::Vector3, {{"in1", hue}, {"in2", saturation}, {"in3", value}}); - NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3); - res.set_input("in", color); - res.set_input("amount", combine); - return res; + return create_node("hsvadjust", NodeItem::Type::Color3, {{"in", color}, {"amount", combine}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc index 693950aa85d..332d3b4e055 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.cc +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -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, fac.val(1.0f) - color); + return fac.blend(color, val(1.0f) - color); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index 4823208e6e1..f8441ba97e6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -475,14 +475,14 @@ NODE_SHADER_MATERIALX_BEGIN BLI_assert_unreachable(); } - NodeItem res = create_node("range", type); - res.set_input("in", value); - res.set_input("inlow", from_min); - res.set_input("inhigh", from_max); - res.set_input("outlow", to_min); - res.set_input("outhigh", to_max); - res.set_input("doclamp", val(bool(map_range->clamp))); - return res; + return create_node("range", + type, + {{"in", value}, + {"inlow", from_min}, + {"inhigh", from_max}, + {"outlow", to_min}, + {"outhigh", to_max}, + {"doclamp", val(bool(map_range->clamp))}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index 434b54515f0..1710842289a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -41,10 +41,7 @@ NODE_SHADER_MATERIALX_BEGIN res = shader2 * fac; } else if (shader1 && shader2) { - res = create_node("mix", to_type_); - res.set_input("fg", shader1); - res.set_input("bg", shader2); - res.set_input("mix", fac); + res = create_node("mix", to_type_, {{"fg", shader1}, {"bg", shader2}, {"mix", fac}}); } break; } diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc index 44c162913f2..86ec4a19885 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc @@ -147,11 +147,9 @@ NODE_SHADER_MATERIALX_BEGIN BLI_assert_unreachable(); } - NodeItem res = create_node("normalmap", NodeItem::Type::Vector3); - res.set_input("in", color); - res.set_input("scale", strength); - res.set_input("space", val(space)); - return res; + return create_node("normalmap", + NodeItem::Type::Vector3, + {{"in", color}, {"scale", strength}, {"space", val(space)}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.cc b/source/blender/nodes/shader/nodes/node_shader_object_info.cc index 44d6286085a..5326d2d73fb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc @@ -38,8 +38,7 @@ NODE_SHADER_MATERIALX_BEGIN std::string name = socket_out_->name; if (name == "Location") { - res = create_node("position", NodeItem::Type::Vector3); - res.set_input("space", val(std::string("world"))); + res = create_node("position", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } /* TODO: This node doesn't have an implementation in MaterialX. * It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8. diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index 1167bfb9677..f9aa8cf13e6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -61,9 +61,7 @@ NODE_SHADER_MATERIALX_BEGIN else { surface = get_input_link("Surface", NodeItem::Type::SurfaceShader); } - NodeItem res = create_node("surfacematerial", NodeItem::Type::Material); - res.set_input("surfaceshader", surface); - return res; + return create_node("surfacematerial", NodeItem::Type::Material, {{"surfaceshader", surface}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb.cc index 5f84b9f8c9e..382ede841da 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc @@ -30,9 +30,7 @@ NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { NodeItem color = get_output_default("Color", NodeItem::Type::Color4); - NodeItem res = create_node("constant", NodeItem::Type::Color4); - res.set_input("value", color); - return res; + return create_node("constant", NodeItem::Type::Color4, {{"value", color}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc index 77407b3b515..59cf2a88873 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc @@ -31,10 +31,7 @@ NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { NodeItem color = get_input_value("Color", NodeItem::Type::Color4); - - NodeItem res = create_node("luminance", NodeItem::Type::Color4); - res.set_input("in", color); - return res; + return create_node("luminance", NodeItem::Type::Color4, {{"in", color}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc index e82856ab18e..eaf7f5f4d93 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc @@ -82,8 +82,7 @@ NODE_SHADER_MATERIALX_BEGIN case NODE_COMBSEP_COLOR_HSV: case NODE_COMBSEP_COLOR_HSL: /* NOTE: HSL is unsupported color model, using HSV instead */ - convert = create_node("rgbtohsv", NodeItem::Type::Color3); - convert.set_input("in", color); + convert = create_node("rgbtohsv", NodeItem::Type::Color3, {{"in", color}}); break; default: BLI_assert_unreachable(); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index b9f0b568e51..4cf874e903e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -153,11 +153,7 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem y = get_input_value("Y", NodeItem::Type::Float); NodeItem z = get_input_value("Z", NodeItem::Type::Float); - NodeItem res = create_node("combine3", NodeItem::Type::Vector3); - res.set_input("in1", x); - res.set_input("in2", y); - res.set_input("in3", z); - return res; + return create_node("combine3", NodeItem::Type::Vector3, {{"in1", x}, {"in2", y}, {"in3", z}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc index 85eeb92aadb..1d5c31818ac 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc @@ -91,15 +91,13 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem anisotropy = get_input_value("Anisotropy", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem res = create_node("subsurface_bsdf", NodeItem::Type::BSDF); - res.set_input("weight", val(1.0f)); - res.set_input("color", color); - res.set_input("radius", radius * scale); - res.set_input("anisotropy", anisotropy); - if (normal) { - res.set_input("normal", normal); - } - return res; + return create_node("subsurface_bsdf", + NodeItem::Type::BSDF, + {{"weight", val(1.0f)}, + {"color", color}, + {"radius", radius * scale}, + {"anisotropy", anisotropy}, + {"normal", normal}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc index 177d235077f..c8e508937ee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc @@ -82,12 +82,10 @@ NODE_SHADER_MATERIALX_BEGIN res = texcoord_node(); } else if (name == "Normal") { - res = create_node("normal", NodeItem::Type::Vector3); - res.set_input("space", val(std::string("world"))); + res = create_node("normal", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } else if (name == "Object") { - res = create_node("position", NodeItem::Type::Vector3); - res.set_input("space", val(std::string("world"))); + res = create_node("position", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } else { res = get_output_default(name, NodeItem::Type::Any); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index 90963a99127..537114b70d7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -238,12 +238,14 @@ NODE_SHADER_MATERIALX_BEGIN BLI_assert_unreachable(); } - res = create_node("image", NodeItem::Type::Color4); + res = create_node("image", + NodeItem::Type::Color4, + {{"texcoord", vector}, + {"filtertype", val(filtertype)}, + {"uaddressmode", val(addressmode)}, + {"vaddressmode", val(addressmode)}}); res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", vector); - res.set_input("filtertype", val(filtertype)); - res.set_input("uaddressmode", val(addressmode)); - res.set_input("vaddressmode", val(addressmode)); + res.node->setName(image_node_name); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index faa16e50cf8..876e072e97d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -267,11 +267,11 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem position = create_node("position", NodeItem::Type::Vector3); position = position * scale; - NodeItem res = create_node("fractal3d", NodeItem::Type::Color3); - res.set_input("position", position); - res.set_input("octaves", val(int(detail.value->asA()))); - res.set_input("lacunarity", lacunarity); - return res; + return create_node("fractal3d", + NodeItem::Type::Color3, + {{"position", position}, + {"octaves", val(int(detail.value->asA()))}, + {"lacunarity", lacunarity}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 01663d11288..e74fcb3252b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -42,9 +42,7 @@ NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { NodeItem value = get_output_default("Value", NodeItem::Type::Float); - NodeItem res = create_node("constant", NodeItem::Type::Float); - res.set_input("value", value); - return res; + return create_node("constant", NodeItem::Type::Float, {{"value", value}}); } #endif NODE_SHADER_MATERIALX_END -- 2.30.2 From 886b414a7c7efcaba7c00a7e6f56114d3bb4ce33 Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Thu, 21 Sep 2023 09:30:59 +0200 Subject: [PATCH 27/40] MaterialX: Implement Gradient Texture node. ### Purpose Add support for Gradient Texture node. ### Technical steps Implemented Gradient Texture node according to existing Blender's implementation, Fixed dotproduct, added `to_type` argument to be able to specify output type of node while using `arithmetic` method. Pull Request: https://projects.blender.org/DagerD/blender/pulls/28 --- .../nodes/shader/materialx/node_item.cc | 8 ++-- .../nodes/shader/materialx/node_item.h | 3 +- .../shader/nodes/node_shader_tex_gradient.cc | 45 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index 8fa84213de7..c1fa1d64bf6 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -233,7 +233,8 @@ 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; }); + NodeItem d = arithmetic( + other, "dotproduct", [](float a, float b) { return a * b; }, Type::Float); if (d.value) { float f = 0.0f; switch (d.type()) { @@ -830,12 +831,13 @@ NodeItem NodeItem::arithmetic(const std::string &category, std::function func) const + std::function func, + Type to_type) const { NodeItem res = empty(); NodeItem item1 = *this; NodeItem item2 = other; - Type to_type = cast_types(item1, item2); + to_type = (to_type == Type::Any) ? cast_types(item1, item2) : to_type; if (to_type == Type::Empty) { return res; } diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index 40be1153031..7cdf8cc59ee 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -127,7 +127,8 @@ class NodeItem { NodeItem arithmetic(const std::string &category, std::function func) const; NodeItem arithmetic(const NodeItem &other, const std::string &category, - std::function func) const; + std::function func, + Type to_type = Type::Any) const; }; template NodeItem NodeItem::val(const T &data) const diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc index dc1b8046e08..989a1e527ec 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -147,6 +147,50 @@ static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder & builder.construct_and_set_matching_fn(tex->gradient_type); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeTexGradient *tex = (NodeTexGradient *)node_->storage; + const int gradient_type = tex->gradient_type; + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + NodeItem res = empty(); + + switch (gradient_type) { + case SHD_BLEND_LINEAR: + res = vector.extract(0); + break; + case SHD_BLEND_QUADRATIC: + res = vector.extract(0); + res = res * res; + break; + case SHD_BLEND_EASING: + res = vector.extract(0).clamp(val(0.0f), val(1.0f)); + 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); + break; + case SHD_BLEND_RADIAL: + res = vector.extract(1).atan2(vector.extract(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)); + res = res * res; + break; + case SHD_BLEND_SPHERICAL: + res = (val(1.0f) - vector.dotproduct(vector).sqrt()).max(val(0.0f)); + break; + default: + BLI_assert_unreachable(); + } + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_gradient_cc void register_node_type_sh_tex_gradient() @@ -163,6 +207,7 @@ void register_node_type_sh_tex_gradient() &ntype, "NodeTexGradient", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_tex_gradient; ntype.build_multi_function = file_ns::sh_node_gradient_tex_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From 2973df8ea72f20652b19649ae96c201392b31e81 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Thu, 21 Sep 2023 10:58:04 +0200 Subject: [PATCH 28/40] MaterialX: split standard_surface into basic nodes ### Purpose Split standard_surface into basic nodes ### Technical steps Standard_surface splitted into basic nodes Pull Request: https://projects.blender.org/DagerD/blender/pulls/26 --- .../nodes/shader/materialx/node_item.h | 5 +- .../nodes/node_shader_bsdf_principled.cc | 356 ++++++++++++++---- .../shader/nodes/node_shader_mix_shader.cc | 2 +- 3 files changed, 286 insertions(+), 77 deletions(-) diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index 7cdf8cc59ee..d1c7cb81d0c 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -51,9 +51,12 @@ class NodeItem { MaterialX::OutputPtr output; private: - MaterialX::GraphElement *graph_; + MaterialX::GraphElement *graph_ = nullptr; public: + /* NOTE: Default constructor added to allow easy work with std::map. + * Don't use this constructor to create NodeItem. */ + NodeItem() = default; NodeItem(MaterialX::GraphElement *graph); ~NodeItem() = default; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index 7ff70e95b30..ada2bb7be86 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -2,6 +2,8 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include + #include "BLI_string.h" #include "node_shader_util.hh" @@ -287,83 +289,287 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node) NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - if (to_type_ != NodeItem::Type::SurfaceShader) { - /* TODO: implement for BSDF and EDF */ - return empty(); + /* NOTE: commented inputs aren't used for node creation. */ + auto bsdf_inputs = [&]() { + return std::map{ + {"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)}, + {"subsurface_radius", get_input_value("Subsurface Radius", NodeItem::Type::Vector3)}, + //{"subsurface_ior", get_input_value("Subsurface IOR", NodeItem::Type::Vector3)}, + {"subsurface_anisotropy", get_input_value("Subsurface Anisotropy", NodeItem::Type::Float)}, + {"metallic", get_input_value("Metallic", NodeItem::Type::Float)}, + {"specular", get_input_value("Specular", NodeItem::Type::Float)}, + {"specular_tint", get_input_value("Specular Tint", NodeItem::Type::Color3)}, + {"roughness", get_input_value("Roughness", NodeItem::Type::Float)}, + {"anisotropic", get_input_value("Anisotropic", NodeItem::Type::Float)}, + {"anisotropic_rotation", get_input_value("Anisotropic Rotation", NodeItem::Type::Float)}, + {"sheen", get_input_value("Sheen", NodeItem::Type::Float)}, + {"sheen_roughness", get_input_value("Sheen Roughness", NodeItem::Type::Float)}, + {"sheen_tint", get_input_value("Sheen Tint", NodeItem::Type::Color3)}, + {"coat", get_input_value("Coat", NodeItem::Type::Float)}, + {"coat_roughness", get_input_value("Coat Roughness", NodeItem::Type::Float)}, + {"coat_ior", get_input_value("Coat IOR", NodeItem::Type::Float)}, + {"coat_tint", get_input_value("Coat Tint", NodeItem::Type::Color3)}, + {"ior", get_input_value("IOR", NodeItem::Type::Float)}, + {"transmission", get_input_value("Transmission", NodeItem::Type::Float)}, + //{"alpha", get_input_value("Alpha", NodeItem::Type::Float)}, + {"normal", get_input_link("Normal", NodeItem::Type::Vector3)}, + {"coat_normal", get_input_link("Coat Normal", NodeItem::Type::Vector3)}, + {"tangent", get_input_link("Tangent", NodeItem::Type::Vector3)}, + }; + }; + + auto edf_inputs = [&]() { + return std::map{ + {"emission", get_input_value("Emission Strength", NodeItem::Type::Float)}, + {"emission_color", get_input_value("Emission", NodeItem::Type::Color3)}}; + }; + + NodeItem res = empty(); + if (to_type_ == NodeItem::Type::BSDF) { + auto in = bsdf_inputs(); + + NodeItem roughness = in["roughness"]; + NodeItem anisotropy = in["anisotropic"]; + NodeItem rotation = in["anisotropic_rotation"]; + 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(); + 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}}); + + n_main_tangent = anisotropy.if_else( + NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent); + } + + NodeItem n_coat_roughness_vector = create_node( + "roughness_anisotropy", + NodeItem::Type::Vector2, + {{"roughness", in["coat_roughness"]}, {"anisotropy", anisotropy}}); + + NodeItem n_coat_bsdf = create_node("dielectric_bsdf", + NodeItem::Type::BSDF, + {{"weight", coat}, + {"tint", in["coat_tint"]}, + {"ior", in["coat_ior"]}, + {"scatter_mode", val(std::string("R"))}, + {"roughness", n_coat_roughness_vector}, + {"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 = anisotropy.if_else( + NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent); + + n_coat_bsdf.set_input("tangent", n_coat_tangent); + } + + NodeItem n_thin_film_bsdf = create_node( + "thin_film_bsdf", NodeItem::Type::BSDF, {{"thickness", val(0.0f)}, {"ior", val(1.5f)}}); + + NodeItem n_artistic_ior = create_node( + "artistic_ior", + NodeItem::Type::Multioutput, + {{"reflectivity", base_color * val(1.0f)}, {"edge_color", base_color * specular}}); + + 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_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, + {{"color", base_color.max(val(0.0f)) ^ n_coat_gamma}, + {"roughness", roughness}, + {"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_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_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_thin_film_layer = create_node( + "layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}}); + + 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}}); + + res = create_node("layer", + NodeItem::Type::BSDF, + {{"top", n_coat_bsdf}, {"base", n_thin_film_layer * n_coat_attenuation}}); + } + 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(); } - NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3); - - NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float); - NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3); - NodeItem subsurface_scale = get_input_value("Subsurface Scale", NodeItem::Type::Float); - - NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float); - NodeItem specular = get_input_value("Specular", NodeItem::Type::Float); - // NodeItem specular_tint = get_input_value("Specular Tint"); - NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); - - /* TODO: use Specular Tint input */ - NodeItem anisotropic = get_input_value("Anisotropic", NodeItem::Type::Float); - NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation", NodeItem::Type::Float); - // anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0) - - NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float); - // sheen_tint = get_input_value("Sheen Tint"); - - NodeItem coat = get_input_value("Coat", NodeItem::Type::Float); - NodeItem coat_roughness = get_input_value("Coat Roughness", NodeItem::Type::Float); - - NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); - - NodeItem transmission = get_input_value("Transmission", NodeItem::Type::Float); - - NodeItem emission = get_input_value("Emission", NodeItem::Type::Color3); - NodeItem emission_strength = get_input_value("Emission Strength", NodeItem::Type::Float); - - NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float); - // transparency = 1.0 - alpha - - NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem coat_normal = get_input_link("Coat Normal", NodeItem::Type::Vector3); - NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3); - - subsurface_radius = subsurface_radius * subsurface_scale; - - /* Creating standard_surface */ - return create_node("standard_surface", - NodeItem::Type::SurfaceShader, - {{"base", val(1.0f)}, - {"base_color", base_color}, - {"diffuse_roughness", roughness}, - {"normal", normal}, - {"tangent", tangent}, - {"metalness", metallic}, - {"specular", specular}, - {"specular_color", base_color}, - {"specular_roughness", roughness}, - {"specular_IOR", ior}, - {"specular_anisotropy", anisotropic}, - {"specular_rotation", anisotropic_rotation}, - {"transmission", transmission}, - {"transmission_color", base_color}, - {"transmission_extra_roughness", roughness}, - {"subsurface", subsurface}, - {"subsurface_color", base_color}, - {"subsurface_radius", subsurface_radius}, - {"subsurface_anisotropy", anisotropic}, - {"sheen", sheen}, - {"sheen_color", base_color}, - {"sheen_roughness", roughness}, - {"coat", coat}, - {"coat_color", base_color}, - {"coat_roughness", coat_roughness}, - {"coat_IOR", ior}, - {"coat_anisotropy", anisotropic}, - {"coat_rotation", anisotropic_rotation}, - {"coat_normal", coat_normal}, - {"emission", emission_strength}, - {"emission_color", emission}}); + return res; } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index 1710842289a..08a671f5cab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -41,7 +41,7 @@ NODE_SHADER_MATERIALX_BEGIN res = shader2 * fac; } else if (shader1 && shader2) { - res = create_node("mix", to_type_, {{"fg", shader1}, {"bg", shader2}, {"mix", fac}}); + res = create_node("mix", to_type_, {{"fg", shader2}, {"bg", shader1}, {"mix", fac}}); } break; } -- 2.30.2 From 6bd07ef717d9b7eb295dc8129996a2702f65b0a0 Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Thu, 21 Sep 2023 11:25:59 +0200 Subject: [PATCH 29/40] MaterialX: Implement Wave Texture node. ### Purpose Add support for Wave Texture node. ### Technical steps Implemented Wave Texture node according to existing Blender's implementation. Utilizing MaterialX "fractal3d" noise instead of Blender's "perlin_fractal" implementation. Adjusted parameter to get results close to Cycles/Eevee. Pull Request: https://projects.blender.org/DagerD/blender/pulls/29 --- .../shader/nodes/node_shader_tex_wave.cc | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc index 0cf86628c81..63b0de98e44 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -219,6 +219,101 @@ static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &buil tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile); } +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 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(); + } + + NodeItem p = vector * scale; + p = (p + val(0.000001f)) * val(0.999999f); + NodeItem n = val(0.0f); + NodeItem value = val(0.0f); + + switch (wave_type) { + case SHD_WAVE_BANDS: + switch (bands_direction) { + case SHD_WAVE_BANDS_DIRECTION_X: + n = p.extract(0) * val(20.0f); + break; + case SHD_WAVE_BANDS_DIRECTION_Y: + n = p.extract(1) * val(20.0f); + break; + case SHD_WAVE_BANDS_DIRECTION_Z: + n = p.extract(2) * val(20.0f); + break; + case SHD_WAVE_BANDS_DIRECTION_DIAGONAL: + n = (p.extract(0) + p.extract(1) + p.extract(2)) * val(10.0f); + break; + default: + BLI_assert_unreachable(); + } + break; + case SHD_WAVE_RINGS: + NodeItem rp = p; + switch (rings_direction) { + case SHD_WAVE_RINGS_DIRECTION_X: + rp = rp * 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)); + break; + case SHD_WAVE_RINGS_DIRECTION_Z: + rp = rp * val(MaterialX::Vector3(1.0f, 1.0f, 0.0f)); + break; + case SHD_WAVE_RINGS_DIRECTION_SPHERICAL: + /* Ignore. */ + break; + default: + BLI_assert_unreachable(); + } + n = rp.dotproduct(rp).sqrt() * 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()))}, + {"lacunarity", val(2.0f)}}); + + switch (wave_profile) { + case SHD_WAVE_PROFILE_SIN: + value = val(0.5f) + val(0.5f) * (n - val(float(M_PI_2))).sin(); + break; + case SHD_WAVE_PROFILE_SAW: + n = n / val(float(M_PI * 2.0f)); + value = n - n.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); + break; + default: + BLI_assert_unreachable(); + } + return value; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_tex_wave_cc void register_node_type_sh_tex_wave() @@ -235,6 +330,7 @@ void register_node_type_sh_tex_wave() node_type_storage(&ntype, "NodeTexWave", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_tex_wave; ntype.build_multi_function = file_ns::sh_node_wave_tex_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From 74afa9c3933c8cd6e99e91b80b8e39f26984aa03 Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Fri, 22 Sep 2023 10:03:22 +0200 Subject: [PATCH 30/40] MaterialX: add support for Vector nodes ### Purpose Add support for Vector nodes. ### Technical steps Fixed normal map color input type to Vector3. Implemented NodeItem method rotate3d. Implemented nodes Added: * Bump * Mapping * Normal * Vector Rotate * Vector Transform Partially implemented (only node implementation): * Vector Displacement * Displacement Not implemented: * Vector Curves Pull Request: https://projects.blender.org/DagerD/blender/pulls/27 --- .../nodes/shader/materialx/node_item.cc | 22 +++++++ .../nodes/shader/materialx/node_item.h | 2 + .../nodes/shader/nodes/node_shader_bump.cc | 29 +++++++++ .../shader/nodes/node_shader_displacement.cc | 16 +++++ .../nodes/shader/nodes/node_shader_mapping.cc | 39 +++++++++++ .../nodes/shader/nodes/node_shader_normal.cc | 15 +++++ .../shader/nodes/node_shader_normal_map.cc | 2 +- .../nodes/node_shader_vector_displacement.cc | 16 +++++ .../shader/nodes/node_shader_vector_rotate.cc | 64 +++++++++++++++++++ .../nodes/node_shader_vector_transform.cc | 63 ++++++++++++++++++ 10 files changed, 267 insertions(+), 1 deletion(-) diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index c1fa1d64bf6..58dbf289aac 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -53,6 +53,9 @@ NodeItem::Type NodeItem::type(const std::string &type_str) if (type_str == "EDF") { return Type::EDF; } + if (type_str == "displacementshader") { + return Type::Displacementshader; + } if (type_str == "surfaceshader") { return Type::SurfaceShader; } @@ -94,6 +97,8 @@ std::string NodeItem::type(Type type) return "BSDF"; case Type::EDF: return "EDF"; + case Type::Displacementshader: + return "displacementshader"; case Type::SurfaceShader: return "surfaceshader"; case Type::Material: @@ -613,6 +618,23 @@ 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) { diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index d1c7cb81d0c..ac1f5ad61df 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -39,6 +39,7 @@ class NodeItem { * NOTE: There are only supported types */ BSDF, EDF, + Displacementshader, SurfaceShader, Material, }; @@ -109,6 +110,7 @@ class NodeItem { /* Useful functions */ NodeItem empty() const; + NodeItem rotate3d(NodeItem rotation, bool invert = false); template NodeItem val(const T &data) const; Type type() const; diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.cc b/source/blender/nodes/shader/nodes/node_shader_bump.cc index d8b008884ad..655ebc9513f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc @@ -71,6 +71,34 @@ static int gpu_shader_bump(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bump", in, out, dheight, GPU_constant(&invert)); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem height = get_input_link("Height", NodeItem::Type::Float); + NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); + + if (!height) { + if (!normal) { + return create_node( + "normal", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); + } + return normal; + } + + NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); + NodeItem distance = get_input_value("Distance", NodeItem::Type::Float); + NodeItem height_normal = create_node( + "heighttonormal", NodeItem::Type::Vector3, {{"in", height}, {"scale", strength}}); + + return create_node("normalmap", + NodeItem::Type::Vector3, + {{"in", height_normal}, + {"scale", node_->custom1 ? distance * val(-1.0f) : distance}, + {"normal", normal}}); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bump_cc /* node type definition */ @@ -84,6 +112,7 @@ void register_node_type_sh_bump() ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_shader_buts_bump; ntype.gpu_fn = file_ns::gpu_shader_bump; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_displacement.cc index cc0fed413ce..2083e7eed77 100644 --- a/source/blender/nodes/shader/nodes/node_shader_displacement.cc +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc @@ -37,6 +37,21 @@ static int gpu_shader_displacement(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_displacement_world", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: Normal input and Space feature don't have an implementation in MaterialX.*/ + NodeItem midlevel = get_input_value("Midlevel", NodeItem::Type::Float); + NodeItem height = get_input_value("Height", NodeItem::Type::Float) - midlevel; + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); + + return create_node("displacement", + NodeItem::Type::Displacementshader, + {{"displacement", height}, {"scale", scale}}); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_displacement_cc /* node type definition */ @@ -50,6 +65,7 @@ void register_node_type_sh_displacement() ntype.declare = file_ns::node_declare; ntype.initfunc = file_ns::node_shader_init_displacement; ntype.gpu_fn = file_ns::gpu_shader_displacement; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.cc b/source/blender/nodes/shader/nodes/node_shader_mapping.cc index 742d32937b7..b1fff267626 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.cc @@ -74,6 +74,44 @@ static void node_shader_update_mapping(bNodeTree *ntree, bNode *node) ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem res = empty(); + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3); + + if (!vector) { + return res; + } + + 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))); + + 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; + default: + BLI_assert_unreachable(); + } + + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_mapping_cc void register_node_type_sh_mapping() @@ -87,6 +125,7 @@ void register_node_type_sh_mapping() ntype.draw_buttons = file_ns::node_shader_buts_mapping; ntype.gpu_fn = file_ns::gpu_shader_mapping; ntype.updatefunc = file_ns::node_shader_update_mapping; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.cc b/source/blender/nodes/shader/nodes/node_shader_normal.cc index 6af7f4316fa..ac1fc498c38 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal.cc +++ b/source/blender/nodes/shader/nodes/node_shader_normal.cc @@ -35,6 +35,20 @@ static int gpu_shader_normal(GPUMaterial *mat, return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem res = get_output_default("Normal", NodeItem::Type::Vector3); + + if (STREQ(socket_out_->name, "Dot")) { + return res.dotproduct(get_input_value("Normal", NodeItem::Type::Vector3)); + } + + return res; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_normal_cc void register_node_type_sh_normal() @@ -46,6 +60,7 @@ void register_node_type_sh_normal() sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_normal; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc index 86ec4a19885..0bd79164ffc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc @@ -126,7 +126,7 @@ NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { NodeShaderNormalMap *normal_map_node = static_cast(node_->storage); - NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + NodeItem color = get_input_value("Color", NodeItem::Type::Vector3); NodeItem strength = get_input_value("Strength", NodeItem::Type::Float); std::string space; diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc index 07cf11433ae..8d0a87ad17d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc @@ -41,6 +41,21 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, } } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + /* NOTE: Midlevel input and Space feature don't have an implementation in MaterialX.*/ + // NodeItem midlevel = get_input_value("midlevel", NodeItem::Type::Float); + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3); + NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); + + return create_node("displacement", + NodeItem::Type::Displacementshader, + {{"displacement", vector}, {"scale", scale}}); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_vector_displacement_cc /* node type definition */ @@ -55,6 +70,7 @@ void register_node_type_sh_vector_displacement() ntype.declare = file_ns::node_declare; ntype.initfunc = file_ns::node_shader_init_vector_displacement; ntype.gpu_fn = file_ns::gpu_shader_vector_displacement; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 68a4314d701..5d71a97def4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -212,6 +212,69 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node) ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector3); + + if (!vector) { + return empty(); + } + + NodeItem angle = empty(); + NodeItem axis = empty(); + NodeItem center = get_input_value("Center", NodeItem::Type::Vector3) * + val(MaterialX::Vector3(1.0f, 1.0f, -1.0f)); + NodeItem res = vector - center; + int mode = node_->custom1; + bool invert = node_->custom1; + + 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); + } + + angle = angle * val(float(180.0f / M_PI)); + angle = invert ? angle * val(-1.0f) : angle; + + switch (mode) { + case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: { + return res.rotate3d(angle, invert) + center; + } + 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: { + axis = val(MaterialX::Vector3(1.0f, 0.0f, 0.0f)); + break; + } + 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: { + axis = val(MaterialX::Vector3(0.0f, 0.0f, -1.0f)); + break; + } + default: { + BLI_assert_unreachable(); + return vector; + } + } + + return create_node("rotate3d", + NodeItem::Type::Vector3, + {{"in", res}, {"amount", angle}, {"axis", axis}}) + + center; +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_vector_rotate_cc void register_node_type_sh_vector_rotate() @@ -226,6 +289,7 @@ void register_node_type_sh_vector_rotate() ntype.gpu_fn = file_ns::gpu_shader_vector_rotate; ntype.updatefunc = file_ns::node_shader_update_vector_rotate; ntype.build_multi_function = file_ns::sh_node_vector_rotate_build_multi_function; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc index d7385147788..a580f5ac52d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc @@ -137,6 +137,68 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, return true; } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + NodeItem res = empty(); + NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node_->storage; + std::string fromspace; + std::string tospace; + std::string category; + NodeItem vector = get_input_value("Vector", NodeItem::Type::Vector3); + + switch (nodeprop->convert_from) { + case SHD_VECT_TRANSFORM_SPACE_WORLD: + fromspace = "world"; + break; + case SHD_VECT_TRANSFORM_SPACE_OBJECT: + fromspace = "object"; + break; + default: + /* NOTE: SHD_VECT_TRANSFORM_SPACE_CAMERA don't have an implementation in MaterialX.*/ + BLI_assert_unreachable(); + return vector; + } + + switch (nodeprop->convert_to) { + case SHD_VECT_TRANSFORM_SPACE_WORLD: + tospace = "world"; + break; + case SHD_VECT_TRANSFORM_SPACE_OBJECT: + tospace = "object"; + break; + default: + /* NOTE: SHD_VECT_TRANSFORM_SPACE_CAMERA don't have an implementation in MaterialX.*/ + BLI_assert_unreachable(); + return vector; + } + + if (fromspace == tospace) { + return vector; + } + + switch (nodeprop->type) { + case SHD_VECT_TRANSFORM_TYPE_POINT: + category = "transformpoint"; + break; + case SHD_VECT_TRANSFORM_TYPE_NORMAL: + category = "transformnormal"; + break; + case SHD_VECT_TRANSFORM_TYPE_VECTOR: + category = "transformvector"; + break; + default: + BLI_assert_unreachable(); + return vector; + } + + return create_node(category, + NodeItem::Type::Vector3, + {{"in", vector}, {"fromspace", val(fromspace)}, {"tospace", val(tospace)}}); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_vector_transform_cc void register_node_type_sh_vect_transform() @@ -152,6 +214,7 @@ void register_node_type_sh_vect_transform() node_type_storage( &ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::gpu_shader_vect_transform; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } -- 2.30.2 From d1492f85929a156184b4d56e9f22f96d18cc5975 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Fri, 22 Sep 2023 18:12:38 +0200 Subject: [PATCH 31/40] MaterialX: make caching image in MaterialX independent from `bf_usd` project ### Purpose Make caching image in MaterialX independent from `bf_usd` project ### Technical steps * Added callback `ExportImageFunction` for image caching * Removed `WITH_HYDRA` from CMakeLists Pull Request: https://projects.blender.org/DagerD/blender/pulls/31 --- source/blender/io/usd/hydra/material.cc | 3 +- source/blender/nodes/shader/CMakeLists.txt | 7 ---- .../nodes/shader/materialx/group_nodes.cc | 10 ++++-- .../nodes/shader/materialx/material.cc | 33 +++++++++++++++---- .../blender/nodes/shader/materialx/material.h | 6 +++- .../nodes/shader/materialx/node_parser.cc | 29 ++++++++++++---- .../nodes/shader/materialx/node_parser.h | 16 +++++++-- .../nodes/node_shader_tex_environment.cc | 14 ++++---- .../shader/nodes/node_shader_tex_image.cc | 14 ++++---- 9 files changed, 89 insertions(+), 43 deletions(-) diff --git a/source/blender/io/usd/hydra/material.cc b/source/blender/io/usd/hydra/material.cc index 9fdf47965a8..afc5048efb2 100644 --- a/source/blender/io/usd/hydra/material.cc +++ b/source/blender/io/usd/hydra/material.cc @@ -36,6 +36,7 @@ #include "intern/usd_exporter_context.h" #include "intern/usd_writer_material.h" #ifdef WITH_MATERIALX +# include "shader/materialx/node_parser.h" # include "shader/materialx/material.h" #endif namespace blender::io::hydra { @@ -79,7 +80,7 @@ void MaterialData::init() #ifdef WITH_MATERIALX if (scene_delegate_->use_materialx) { MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx( - scene_delegate_->depsgraph, (Material *)id); + 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() diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index f437420e5d4..0caf0e164c5 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -22,13 +22,6 @@ set(INC ${CMAKE_BINARY_DIR}/source/blender/makesrna ) -if(WITH_HYDRA) - list(APPEND INC - ../../io/usd - ) - add_definitions(-DWITH_HYDRA) -endif() - set(INC_SYS ) diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc index 7f13fb108ae..9f6778ca01c 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.cc +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -32,8 +32,14 @@ NodeItem GroupNodeParser::compute() #endif NodeItem out = - GroupOutputNodeParser( - graph, depsgraph_, material_, node_out, socket_out_, NodeItem::Type::Any, this) + GroupOutputNodeParser(graph, + depsgraph_, + material_, + node_out, + socket_out_, + NodeItem::Type::Any, + this, + export_image_fn_) .compute_full(); #ifdef USE_MATERIALX_NODEGRAPH diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 4da740b5431..755c937ad74 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -54,7 +54,9 @@ class DefaultMaterialNodeParser : public NodeParser { } }; -MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material) +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, + Material *material, + ExportImageFunction export_image_fn) { CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name); @@ -63,19 +65,36 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater material->nodetree->ensure_topology_cache(); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); if (output_node) { - NodeParserData data = { - doc.get(), depsgraph, material, NodeItem::Type::Material, nullptr, NodeItem(doc.get())}; + NodeParserData data = {doc.get(), + depsgraph, + material, + NodeItem::Type::Material, + nullptr, + NodeItem(doc.get()), + export_image_fn}; output_node->typeinfo->materialx_fn(&data, output_node, nullptr); } else { - DefaultMaterialNodeParser( - doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material, nullptr) + DefaultMaterialNodeParser(doc.get(), + depsgraph, + material, + nullptr, + nullptr, + NodeItem::Type::Material, + nullptr, + export_image_fn) .compute_error(); } } else { - DefaultMaterialNodeParser( - doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material, nullptr) + DefaultMaterialNodeParser(doc.get(), + depsgraph, + material, + nullptr, + nullptr, + NodeItem::Type::Material, + nullptr, + export_image_fn) .compute(); } diff --git a/source/blender/nodes/shader/materialx/material.h b/source/blender/nodes/shader/materialx/material.h index 760b6cdef33..d0a4a7e6a31 100644 --- a/source/blender/nodes/shader/materialx/material.h +++ b/source/blender/nodes/shader/materialx/material.h @@ -9,8 +9,12 @@ struct Depsgraph; struct Material; +class ExportImageFunction; + namespace blender::nodes::materialx { -MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); +MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, + Material *material, + ExportImageFunction export_image_fn); } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index 158a8be3351..e22681cbe63 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -20,14 +20,16 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph, const bNode *node, const bNodeSocket *socket_out, NodeItem::Type to_type, - GroupNodeParser *group_parser) + GroupNodeParser *group_parser, + ExportImageFunction export_image_fn) : graph_(graph), depsgraph_(depsgraph), material_(material), node_(node), socket_out_(socket_out), to_type_(to_type), - group_parser_(group_parser) + group_parser_(group_parser), + export_image_fn_(export_image_fn) { } @@ -207,13 +209,25 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to } if (from_node->is_group()) { - return GroupNodeParser( - graph_, depsgraph_, material_, from_node, link->fromsock, to_type, group_parser_) + return GroupNodeParser(graph_, + depsgraph_, + material_, + from_node, + link->fromsock, + to_type, + group_parser_, + export_image_fn_) .compute_full(); } if (from_node->is_group_input()) { - return GroupInputNodeParser( - graph_, depsgraph_, material_, from_node, link->fromsock, to_type, group_parser_) + return GroupInputNodeParser(graph_, + depsgraph_, + material_, + from_node, + link->fromsock, + to_type, + group_parser_, + export_image_fn_) .compute_full(); } @@ -225,7 +239,8 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to return empty(); } - NodeParserData data = {graph_, depsgraph_, material_, to_type, group_parser_, empty()}; + NodeParserData data = { + graph_, depsgraph_, material_, to_type, group_parser_, empty(), export_image_fn_}; from_node->typeinfo->materialx_fn(&data, const_cast(from_node), link->fromsock); return data.result; } diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index eaaa5c1d35b..4bc332442c6 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -18,6 +18,8 @@ extern struct CLG_LogRef *LOG_MATERIALX_SHADER; class GroupNodeParser; +using ExportImageFunction = std::function; + class NodeParser { protected: MaterialX::GraphElement *graph_; @@ -27,6 +29,7 @@ class NodeParser { const bNodeSocket *socket_out_; NodeItem::Type to_type_; GroupNodeParser *group_parser_; + ExportImageFunction export_image_fn_; public: NodeParser(MaterialX::GraphElement *graph, @@ -35,7 +38,8 @@ class NodeParser { const bNode *node, const bNodeSocket *socket_out, NodeItem::Type to_type, - GroupNodeParser *group_parser); + GroupNodeParser *group_parser, + ExportImageFunction export_image_fn); virtual ~NodeParser() = default; virtual NodeItem compute() = 0; @@ -82,6 +86,7 @@ struct NodeParserData { NodeItem::Type to_type; GroupNodeParser *group_parser; NodeItem result; + ExportImageFunction export_image_fn; }; #define NODE_SHADER_MATERIALX_BEGIN \ @@ -102,7 +107,14 @@ struct NodeParserData { { \ materialx::NodeParserData *d = reinterpret_cast(data); \ d->result = MaterialXNodeParser( \ - d->graph, d->depsgraph, d->material, node, out, d->to_type, d->group_parser) \ + d->graph, \ + d->depsgraph, \ + d->material, \ + node, \ + out, \ + d->to_type, \ + d->group_parser, \ + d->export_image_fn) \ .compute_full(); \ } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index 30ad01b489f..feaa0351d0b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -11,8 +11,6 @@ #include "IMB_colormanagement.h" -#include "hydra/image.h" - #include "DEG_depsgraph_query.h" namespace blender::nodes::node_shader_tex_environment_cc { @@ -142,13 +140,13 @@ NODE_SHADER_MATERIALX_BEGIN } NodeTexEnvironment *tex_env = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains - * pretty general code, so could be moved from bf_usd project. */ - std::string image_path = io::hydra::cache_or_get_image_file( - bmain, scene, image, &tex_env->iuser); + std::string image_path = image->id.name; + if (export_image_fn_) { + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); + image_path = export_image_fn_(bmain, scene, image, &tex_env->iuser); + } NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); if (!vector) { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index 537114b70d7..19f24f6c9cb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -11,8 +11,6 @@ #include "IMB_colormanagement.h" -#include "hydra/image.h" - #include "DEG_depsgraph_query.h" namespace blender::nodes::node_shader_tex_image_cc { @@ -191,13 +189,13 @@ NODE_SHADER_MATERIALX_BEGIN Image *image = (Image *)node_->id; if (image) { NodeTexImage *tex_image = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file - * contains pretty general code, so could be moved from bf_usd project. */ - std::string image_path = io::hydra::cache_or_get_image_file( - bmain, scene, image, &tex_image->iuser); + std::string image_path = image->id.name; + if (export_image_fn_) { + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); + image_path = export_image_fn_(bmain, scene, image, &tex_image->iuser); + } NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); if (!vector) { -- 2.30.2 From 483728b7043bf9221ea471dc833e6fc100a21349 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Fri, 22 Sep 2023 18:22:58 +0200 Subject: [PATCH 32/40] Code improvements + Mix node ### Purpose After last merged PRs some code has to be improved. Implement Mix node. ### Technical steps 1. Improvements in NodeItem: - `blend()` -> `mix()` + shaders + mix node usage - `extract()` -> `operator[]` - implemented `length()`, `to_vector()`, `normalize()`, `rotate()`, fixed `dotproduct()` - improvements in math functions. 2. Implemented node Mix 3. Improved code in BSDFPrincipled, TexWave, TexGradient, Mapping, VectorRotate. 4. Code adjustments. 5. Fixed/added comments. 6. Changed order of getting shader type in MaterialOutput: SurfaceShader starts first. Adjusted Add, Mix shaders. Pull Request: https://projects.blender.org/DagerD/blender/pulls/30 --- source/blender/io/usd/hydra/material.cc | 2 +- .../nodes/shader/materialx/node_item.cc | 224 +++++++--- .../nodes/shader/materialx/node_item.h | 24 +- .../nodes/shader/materialx/node_parser.cc | 13 +- .../nodes/shader/materialx/node_parser.h | 21 +- .../shader/nodes/node_shader_add_shader.cc | 45 +- .../nodes/node_shader_bsdf_principled.cc | 416 ++++++++---------- .../nodes/shader/nodes/node_shader_gamma.cc | 1 + .../nodes/shader/nodes/node_shader_invert.cc | 2 +- .../nodes/shader/nodes/node_shader_mapping.cc | 46 +- .../nodes/shader/nodes/node_shader_mix.cc | 54 +++ .../nodes/shader/nodes/node_shader_mix_rgb.cc | 10 - .../shader/nodes/node_shader_mix_shader.cc | 48 +- .../nodes/node_shader_output_material.cc | 25 +- .../shader/nodes/node_shader_sepcomb_color.cc | 2 +- .../shader/nodes/node_shader_sepcomb_xyz.cc | 2 +- .../shader/nodes/node_shader_tex_checker.cc | 2 +- .../shader/nodes/node_shader_tex_gradient.cc | 10 +- .../shader/nodes/node_shader_tex_image.cc | 2 +- .../shader/nodes/node_shader_tex_wave.cc | 75 ++-- .../shader/nodes/node_shader_vector_rotate.cc | 52 +-- 21 files changed, 580 insertions(+), 496 deletions(-) diff --git a/source/blender/io/usd/hydra/material.cc b/source/blender/io/usd/hydra/material.cc index afc5048efb2..095ab4f1bbc 100644 --- a/source/blender/io/usd/hydra/material.cc +++ b/source/blender/io/usd/hydra/material.cc @@ -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; diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index 58dbf289aac..bcb7bdf52f9 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -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(); + break; + case Type::Vector2: + v = value->asA()[index]; + case Type::Vector3: + v = value->asA()[index]; + break; + case Type::Vector4: + v = value->asA()[index]; + break; + case Type::Color3: + v = value->asA()[index]; + break; + case Type::Color4: + v = value->asA()[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,56 +286,86 @@ 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; float f = 0.0f; switch (d.type()) { case Type::Float: { - f = value->asA(); + f = d.value->asA(); break; } case Type::Vector2: { - auto v = value->asA(); + auto v = d.value->asA(); f = v[0] + v[1]; break; } case Type::Vector3: { - auto v = value->asA(); + auto v = d.value->asA(); f = v[0] + v[1] + v[2]; break; } case Type::Vector4: { - auto v = value->asA(); + auto v = d.value->asA(); f = v[0] + v[1] + v[2] + v[3]; break; } case Type::Color3: { - auto v = value->asA(); + auto v = d.value->asA(); f = v[0] + v[1] + v[2]; break; } case Type::Color4: { - auto v = value->asA(); + auto v = d.value->asA(); f = v[0] + v[1] + v[2] + v[3]; break; } default: 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 { - 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 @@ -295,64 +373,95 @@ 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::functiontype(); - 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>; @@ -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 NodeItem val(const T &data) const; Type type() const; diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index e22681cbe63..2f14a971ecb 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -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; } diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index 4bc332442c6..6a93ad38f0f 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -20,6 +20,10 @@ class GroupNodeParser; using ExportImageFunction = std::function; +/** + * 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 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 NodeItem NodeParser::val(const T &data) const return empty().val(data); } -/* +/** * Defines for including MaterialX node parsing code into node_shader_.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; diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc index 7f5ba0162d7..6e0e0a81a51 100644 --- a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc @@ -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: { - 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(); + if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { + return empty(); } - 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 NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index ada2bb7be86..6a8b16ef14b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -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; + /* NOTE: commented inputs aren't used for node creation. */ - auto bsdf_inputs = [&]() { - return std::map{ + 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,255 +322,225 @@ NODE_SHADER_MATERIALX_BEGIN }; }; - auto edf_inputs = [&]() { - return std::map{ + 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) { - auto in = bsdf_inputs(); - NodeItem roughness = in["roughness"]; - NodeItem anisotropy = in["anisotropic"]; - NodeItem rotation = in["anisotropic_rotation"]; - 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"]; + switch (to_type_) { + case NodeItem::Type::BSDF: { + auto in = bsdf_inputs(); - 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 roughness = in["roughness"]; + NodeItem anisotropy = in["anisotropic"]; + NodeItem rotation = in["anisotropic_rotation"] * val(360.0f); + 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_tangent_rotate_normalize = create_node( - "normalize", NodeItem::Type::Vector3, {{"in", n_tangent_rotate}}); + NodeItem n_main_tangent = empty(); + 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::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent); - } + NodeItem n_coat_roughness_vector = create_node( + "roughness_anisotropy", + NodeItem::Type::Vector2, + {{"roughness", in["coat_roughness"]}, {"anisotropy", anisotropy}}); - NodeItem n_coat_roughness_vector = create_node( - "roughness_anisotropy", - NodeItem::Type::Vector2, - {{"roughness", in["coat_roughness"]}, {"anisotropy", anisotropy}}); + NodeItem n_coat_bsdf = create_node("dielectric_bsdf", + NodeItem::Type::BSDF, + {{"weight", coat}, + {"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", - NodeItem::Type::BSDF, - {{"weight", coat}, - {"tint", in["coat_tint"]}, - {"ior", in["coat_ior"]}, - {"scatter_mode", val(std::string("R"))}, - {"roughness", n_coat_roughness_vector}, - {"normal", coat_normal}}); + if (tangent && coat_normal) { + 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); - 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}}); + n_coat_bsdf.set_input("tangent", n_coat_tangent); + } - NodeItem n_coat_tangent_rotate_normalize = create_node( - "normalize", NodeItem::Type::Vector3, {{"in", n_coat_tangent_rotate}}); + NodeItem n_thin_film_bsdf = create_node( + "thin_film_bsdf", NodeItem::Type::BSDF, {{"thickness", val(0.0f)}, {"ior", val(1.5f)}}); - NodeItem n_coat_tangent = anisotropy.if_else( - NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent); + NodeItem n_artistic_ior = create_node( + "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( - "thin_film_bsdf", NodeItem::Type::BSDF, {{"thickness", val(0.0f)}, {"ior", val(1.5f)}}); + NodeItem n_coat_affect_roughness_multiply2 = coat * val(0.0f) * in["coat_roughness"]; + NodeItem n_coat_affected_roughness = n_coat_affect_roughness_multiply2.mix(roughness, + val(1.0f)); - NodeItem n_artistic_ior = create_node( - "artistic_ior", - NodeItem::Type::Multioutput, - {{"reflectivity", base_color * val(1.0f)}, {"edge_color", base_color * specular}}); + NodeItem n_main_roughness = create_node( + "roughness_anisotropy", + NodeItem::Type::Vector2, + {{"roughness", n_coat_affected_roughness}, {"anisotropy", anisotropy}}); - 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_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 n_metal_bsdf = create_node("conductor_bsdf", NodeItem::Type::BSDF, - {{"color", base_color.max(val(0.0f)) ^ n_coat_gamma}, - {"roughness", roughness}, - {"weight", val(1.0f)}, + {{"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 = 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}}); - NodeItem n_subsurface_mix = create_node( - "mix", - NodeItem::Type::BSDF, - {{"fg", n_selected_subsurface_bsdf}, {"bg", n_diffuse_bsdf}, {"mix", in["subsurface"]}}); + NodeItem n_diffuse_bsdf = create_node("oren_nayar_diffuse_bsdf", + NodeItem::Type::BSDF, + {{"color", base_color.max(val(0.0f)) ^ n_coat_gamma}, + {"roughness", roughness}, + {"weight", val(1.0f)}, + {"normal", normal}}); - NodeItem n_sheen_layer = create_node( - "layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}}); + NodeItem n_subsurface_mix = in["subsurface"].mix(n_diffuse_bsdf, n_subsurface_bsdf); - NodeItem n_transmission_mix = create_node( - "mix", - NodeItem::Type::BSDF, - {{"fg", n_transmission_bsdf}, {"bg", n_sheen_layer}, {"mix", in["transmission"]}}); + NodeItem n_sheen_layer = create_node( + "layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}}); - NodeItem n_specular_layer = create_node( - "layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}}); + NodeItem n_transmission_mix = in["transmission"].mix(n_sheen_layer, n_transmission_bsdf); - NodeItem n_metalness_mix = create_node( - "mix", - NodeItem::Type::BSDF, - {{"fg", n_metal_bsdf}, {"bg", n_specular_layer}, {"mix", in["metallic"]}}); + NodeItem n_specular_layer = create_node( + "layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}}); - NodeItem n_thin_film_layer = create_node( - "layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}}); + NodeItem n_metalness_mix = in["metallic"].mix(n_specular_layer, n_metal_bsdf); - NodeItem n_opacity_luminance = create_node( - "luminance", NodeItem::Type::Color3, {{"in", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))}}); + NodeItem n_thin_film_layer = create_node( + "layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}}); - 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_opacity_luminance = create_node( + "luminance", NodeItem::Type::Color3, {{"in", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))}}); - res = create_node("layer", - NodeItem::Type::BSDF, - {{"top", n_coat_bsdf}, {"base", n_thin_film_layer * n_coat_attenuation}}); + 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; + } + + 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; } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.cc b/source/blender/nodes/shader/nodes/node_shader_gamma.cc index 13964192252..96dd74475ab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.cc +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.cc @@ -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 { diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc index 332d3b4e055..8246662d3ec 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.cc +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -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 diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.cc b/source/blender/nodes/shader/nodes/node_shader_mapping.cc index b1fff267626..9937c02cd17 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.cc @@ -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 diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc index 54ed933a6f2..54a8affb561 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc @@ -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); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index 23ab08377e1..457ec46a091 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -150,15 +150,6 @@ static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &build builder.construct_and_set_matching_fn(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); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index 08a671f5cab..249d4f85c7a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -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); - 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(); + if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { + return empty(); } - 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 NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index f9aa8cf13e6..b405c40e8af 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -46,20 +46,19 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - 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) { - surface.set_input("bsdf", bsdf); + 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); + if (bsdf || edf) { + surface = create_node("surface", NodeItem::Type::SurfaceShader); + 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}}); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc index eaf7f5f4d93..32c1e0def8d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc @@ -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 diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index 4cf874e903e..b387a28d35b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -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 diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc index 40dd136fafc..4fe06cd5094 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc @@ -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 diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc index 989a1e527ec..7dd9ad194bb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -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)); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index 19f24f6c9cb..c81dbd6cf6b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -248,7 +248,7 @@ NODE_SHADER_MATERIALX_BEGIN } if (STREQ(socket_out_->name, "Alpha")) { - res = res.extract(3); + res = res[3]; } return res; } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc index 63b0de98e44..73b0a97e65a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -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()))}, + {"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()))}, - {"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 diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 5d71a97def4..c93cac85b81 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -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) * 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 -- 2.30.2 From 2e5b34b6ae7bc634fb99290bc0c4fdc1874a7763 Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Fri, 22 Sep 2023 18:37:29 +0200 Subject: [PATCH 33/40] MaterialX: Fix group nodes. ### Purpose https://projects.blender.org/blender/blender/pulls/111765#issuecomment-1026764 * In the default startup .blend, putting the Principled BSDF node in a group doesn't seem to work here. The cube renders white instead of the specified base color. * The shader/node_group_color.blend renders white when it should be green, ignoring the color set on the group. ### Technical steps * Specified `to_type_` for `GroupOutputNodeParser`. * Improved `GroupInputNodeParser::compute()`. * Improved `GroupOutputNodeParser::compute()`. Pull Request: https://projects.blender.org/DagerD/blender/pulls/32 --- source/blender/nodes/shader/materialx/group_nodes.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc index 9f6778ca01c..6b7d6715491 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.cc +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "group_nodes.h" +#include "node_item.h" #include "node_parser.h" #include "BLI_vector.hh" @@ -37,7 +38,7 @@ NodeItem GroupNodeParser::compute() material_, node_out, socket_out_, - NodeItem::Type::Any, + to_type_, this, export_image_fn_) .compute_full(); @@ -79,7 +80,10 @@ NodeItem GroupOutputNodeParser::compute() } return outputs[socket_out_->index()]; #else - return get_input_value(socket_out_->index(), NodeItem::Type::Any); + if (NodeItem::is_arithmetic(to_type_)) { + return get_input_value(socket_out_->index(), to_type_); + } + return get_input_link(socket_out_->index(), to_type_); #endif } @@ -121,6 +125,9 @@ NodeItem GroupInputNodeParser::compute() } return create_input("input" + std::to_string(socket_out_->index() + 1), value); #else + if (NodeItem::is_arithmetic(to_type_)) { + return group_parser_->get_input_value(socket_out_->index(), to_type_); + } return group_parser_->get_input_link(socket_out_->index(), to_type_); #endif } -- 2.30.2 From 1132957f48522d17eda2aefd7f655c0942c5d4c9 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Sun, 24 Sep 2023 07:42:09 +0200 Subject: [PATCH 34/40] Fix linux build ### Purpose Errors in linux build https://builder.blender.org/admin/#/builders/132/builds/2398. Issues in group nodes. ### Technical steps 1. Fixed linux build: set math functions names to convenience. 2. Fixed some issues in group nodes. Made better naming of inputs and outputs in `nodegraph` for group node. 3. `make format` Co-authored-by: Vasyl-Pidhirskyi Pull Request: https://projects.blender.org/DagerD/blender/pulls/33 --- .../nodes/shader/materialx/group_nodes.cc | 83 ++++++++++++------- .../nodes/shader/materialx/group_nodes.h | 28 +++++-- .../nodes/shader/materialx/node_item.cc | 31 ++++--- .../nodes/shader/materialx/node_parser.cc | 20 +++-- .../nodes/shader/materialx/node_parser.h | 9 +- 5 files changed, 110 insertions(+), 61 deletions(-) diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc index 6b7d6715491..dac98d674da 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.cc +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -3,13 +3,27 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "group_nodes.h" -#include "node_item.h" #include "node_parser.h" #include "BLI_vector.hh" namespace blender::nodes::materialx { +GroupNodeParser::GroupNodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node, + const bNodeSocket *socket_out, + NodeItem::Type to_type, + GroupNodeParser *group_parser, + ExportImageFunction export_image_fn, + bool use_group_default) + : NodeParser( + graph, depsgraph, material, node, socket_out, to_type, group_parser, export_image_fn), + use_group_default_(use_group_default) +{ +} + NodeItem GroupNodeParser::compute() { NodeItem res = empty(); @@ -32,16 +46,16 @@ NodeItem GroupNodeParser::compute() graph = group_graph.get(); #endif - NodeItem out = - GroupOutputNodeParser(graph, + NodeItem out = GroupOutputNodeParser(graph, depsgraph_, material_, node_out, socket_out_, to_type_, this, - export_image_fn_) - .compute_full(); + export_image_fn_, + use_group_default_) + .compute_full(); #ifdef USE_MATERIALX_NODEGRAPH /* We have to be in NodeParser's graph_, therefore copying output */ @@ -66,7 +80,8 @@ NodeItem GroupOutputNodeParser::compute() #ifdef USE_MATERIALX_NODEGRAPH Vector values; for (auto socket_in : node_->input_sockets()) { - NodeItem value = get_input_value(socket_in->index(), NodeItem::Type::Any); + NodeItem value = get_input_value( + socket_in->index(), NodeItem::is_arithmetic(to_type_) ? NodeItem::Type::Any : to_type_); if (value.value) { value = create_node("constant", value.type(), {{"value", value}}); } @@ -75,12 +90,12 @@ NodeItem GroupOutputNodeParser::compute() Vector outputs; for (int i = 0; i < values.size(); ++i) { if (values[i]) { - outputs.append(create_output("output" + std::to_string(i + 1), values[i])); + outputs.append(create_output(out_name(node_->input_sockets()[i]), values[i])); } } return outputs[socket_out_->index()]; #else - if (NodeItem::is_arithmetic(to_type_)) { + if (use_group_default_) { return get_input_value(socket_out_->index(), to_type_); } return get_input_link(socket_out_->index(), to_type_); @@ -89,15 +104,6 @@ NodeItem GroupOutputNodeParser::compute() NodeItem GroupOutputNodeParser::compute_full() { -#ifdef USE_MATERIALX_NODEGRAPH - NodeItem res = empty(); - - /* Checking if output was already computed */ - res.output = graph_->getOutput("output" + std::to_string(socket_out_->index() + 1)); - if (res.output) { - return res; - } - CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d] => %s", @@ -105,6 +111,15 @@ NodeItem GroupOutputNodeParser::compute_full() node_->typeinfo->type, NodeItem::type(to_type_).c_str()); +#ifdef USE_MATERIALX_NODEGRAPH + NodeItem res = empty(); + + /* Checking if output was already computed */ + res.output = graph_->getOutput(out_name(socket_out_)); + if (res.output) { + return res; + } + res = compute(); return res; #else @@ -112,6 +127,11 @@ NodeItem GroupOutputNodeParser::compute_full() #endif } +std::string GroupOutputNodeParser::out_name(const bNodeSocket *out_socket) +{ + return MaterialX::createValidName(std::string("out_") + out_socket->name); +} + NodeItem GroupInputNodeParser::compute() { #ifdef USE_MATERIALX_NODEGRAPH @@ -121,11 +141,11 @@ NodeItem GroupInputNodeParser::compute() } if (value.value) { - value = create_node("constant", value.type(), {{"value", value}}); + value = group_parser_->create_node("constant", value.type(), {{"value", value}}); } - return create_input("input" + std::to_string(socket_out_->index() + 1), value); + return create_input(in_name(), value); #else - if (NodeItem::is_arithmetic(to_type_)) { + if (use_group_default_) { return group_parser_->get_input_value(socket_out_->index(), to_type_); } return group_parser_->get_input_link(socket_out_->index(), to_type_); @@ -134,15 +154,6 @@ NodeItem GroupInputNodeParser::compute() NodeItem GroupInputNodeParser::compute_full() { -#ifdef USE_MATERIALX_NODEGRAPH - NodeItem res = empty(); - - /* Checking if output was already computed */ - res.input = graph_->getInput("input" + std::to_string(socket_out_->index() + 1)); - if (res.input) { - return res; - } - CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d] => %s", @@ -150,6 +161,15 @@ NodeItem GroupInputNodeParser::compute_full() node_->typeinfo->type, NodeItem::type(to_type_).c_str()); +#ifdef USE_MATERIALX_NODEGRAPH + NodeItem res = empty(); + + /* Checking if input was already computed */ + res.input = graph_->getInput(in_name()); + if (res.input) { + return res; + } + res = compute(); return res; #else @@ -157,4 +177,9 @@ NodeItem GroupInputNodeParser::compute_full() #endif } +std::string GroupInputNodeParser::in_name() const +{ + return MaterialX::createValidName(std::string("in_") + socket_out_->name); +} + } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/group_nodes.h b/source/blender/nodes/shader/materialx/group_nodes.h index a486a4af5fd..6072f6aa906 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.h +++ b/source/blender/nodes/shader/materialx/group_nodes.h @@ -15,27 +15,43 @@ namespace blender::nodes::materialx { class GroupInputNodeParser; class GroupNodeParser : public NodeParser { - friend NodeParser; friend GroupInputNodeParser; + protected: + bool use_group_default_; + public: - using NodeParser::NodeParser; + GroupNodeParser(MaterialX::GraphElement *graph, + const Depsgraph *depsgraph, + const Material *material, + const bNode *node, + const bNodeSocket *socket_out, + NodeItem::Type to_type, + GroupNodeParser *group_parser, + ExportImageFunction export_image_fn, + bool use_group_default); NodeItem compute() override; NodeItem compute_full() override; }; -class GroupOutputNodeParser : public NodeParser { +class GroupOutputNodeParser : public GroupNodeParser { public: - using NodeParser::NodeParser; + using GroupNodeParser::GroupNodeParser; NodeItem compute() override; NodeItem compute_full() override; + + private: + static std::string out_name(const bNodeSocket *out_socket); }; -class GroupInputNodeParser : public NodeParser { +class GroupInputNodeParser : public GroupNodeParser { public: - using NodeParser::NodeParser; + using GroupNodeParser::GroupNodeParser; NodeItem compute() override; NodeItem compute_full() override; + + private: + std::string in_name() const; }; } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index bcb7bdf52f9..d65332fdb02 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -174,12 +174,12 @@ NodeItem NodeItem::operator/(const NodeItem &other) const NodeItem NodeItem::operator%(const NodeItem &other) const { return arithmetic( - other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmodf(a, b); }); + other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmod(a, b); }); } 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::pow(a, b); }); } NodeItem NodeItem::operator[](int index) const @@ -245,17 +245,17 @@ bool NodeItem::operator!=(const NodeItem &other) const NodeItem NodeItem::abs() const { - return arithmetic("absval", [](float a) { return std::fabsf(a); }); + return arithmetic("absval", [](float a) { return std::abs(a); }); } NodeItem NodeItem::floor() const { - return arithmetic("floor", [](float a) { return std::floorf(a); }); + return arithmetic("floor", [](float a) { return std::floor(a); }); } NodeItem NodeItem::ceil() const { - return arithmetic("ceil", [](float a) { return std::ceilf(a); }); + return arithmetic("ceil", [](float a) { return std::ceil(a); }); } NodeItem NodeItem::length() const @@ -400,38 +400,37 @@ NodeItem NodeItem::rotate(const NodeItem &angle_xyz, bool invert) NodeItem NodeItem::sin() const { - return to_vector().arithmetic("sin", [](float a) { return std::sinf(a); }); + return to_vector().arithmetic("sin", [](float a) { return std::sin(a); }); } NodeItem NodeItem::cos() const { - return to_vector().arithmetic("cos", [](float a) { return std::cosf(a); }); + return to_vector().arithmetic("cos", [](float a) { return std::cos(a); }); } NodeItem NodeItem::tan() const { - return to_vector().arithmetic("tan", [](float a) { return std::tanf(a); }); + return to_vector().arithmetic("tan", [](float a) { return std::tan(a); }); } NodeItem NodeItem::asin() const { - return to_vector().arithmetic("asin", [](float a) { return std::asinf(a); }); + return to_vector().arithmetic("asin", [](float a) { return std::asin(a); }); } NodeItem NodeItem::acos() const { - return to_vector().arithmetic("acos", [](float a) { return std::acosf(a); }); + return to_vector().arithmetic("acos", [](float a) { return std::acos(a); }); } NodeItem NodeItem::atan() const { - return to_vector().arithmetic("atan", [](float a) { return std::atanf(a); }); + return to_vector().arithmetic("atan", [](float a) { return std::atan(a); }); } NodeItem NodeItem::atan2(const NodeItem &other) const { - return to_vector().arithmetic( - other, "atan2", [](float a, float b) { return std::atan2f(a, b); }); + return to_vector().arithmetic(other, "atan2", [](float a, float b) { return std::atan2(a, b); }); } NodeItem NodeItem::sinh() const @@ -456,12 +455,12 @@ NodeItem NodeItem::tanh() const NodeItem NodeItem::ln() const { - return to_vector().arithmetic("ln", [](float a) { return std::logf(a); }); + return to_vector().arithmetic("ln", [](float a) { return std::log(a); }); } NodeItem NodeItem::sqrt() const { - return to_vector().arithmetic("sqrt", [](float a) { return std::sqrtf(a); }); + return to_vector().arithmetic("sqrt", [](float a) { return std::sqrt(a); }); } NodeItem NodeItem::sign() const @@ -471,7 +470,7 @@ NodeItem NodeItem::sign() const NodeItem NodeItem::exp() const { - return to_vector().arithmetic("exp", [](float a) { return std::expf(a); }); + return to_vector().arithmetic("exp", [](float a) { return std::exp(a); }); } NodeItem NodeItem::convert(Type to_type) const diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index 2f14a971ecb..beedcab3471 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -115,12 +115,12 @@ NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type) NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type) { - return get_input_link(node_->input_by_identifier(name), to_type); + return get_input_link(node_->input_by_identifier(name), to_type, false); } NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type) { - return get_input_link(node_->input_socket(index), to_type); + return get_input_link(node_->input_socket(index), to_type, false); } NodeItem NodeParser::get_input_value(const std::string &name, NodeItem::Type to_type) @@ -167,6 +167,10 @@ NodeItem NodeParser::texcoord_node(NodeItem::Type type) NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_type) { NodeItem res = empty(); + if (!NodeItem::is_arithmetic(to_type) && to_type != NodeItem::Type::Any) { + return res; + } + switch (socket.type) { case SOCK_CUSTOM: /* Return empty */ @@ -195,7 +199,9 @@ NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_ty return res.convert(to_type); } -NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to_type) +NodeItem NodeParser::get_input_link(const bNodeSocket &socket, + NodeItem::Type to_type, + bool use_group_default) { const bNodeLink *link = socket.link; if (!(link && link->is_used())) { @@ -221,7 +227,8 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to link->fromsock, to_type, group_parser_, - export_image_fn_) + export_image_fn_, + use_group_default) .compute_full(); } if (from_node->is_group_input()) { @@ -232,7 +239,8 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to link->fromsock, to_type, group_parser_, - export_image_fn_) + export_image_fn_, + use_group_default) .compute_full(); } @@ -252,7 +260,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type to_type) { - NodeItem res = get_input_link(socket, to_type); + NodeItem res = get_input_link(socket, to_type, true); if (!res) { res = get_default(socket, to_type); } diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index 6a93ad38f0f..83a09aa5b76 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -18,7 +18,7 @@ extern struct CLG_LogRef *LOG_MATERIALX_SHADER; class GroupNodeParser; -using ExportImageFunction = std::function; +using ExportImageFunction = std::function; /** * This is base abstraction class for parsing Blender nodes into MaterialX nodes. @@ -71,7 +71,9 @@ class NodeParser { private: NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type); - NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type); + NodeItem get_input_link(const bNodeSocket &socket, + NodeItem::Type to_type, + bool use_group_default); NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type); }; @@ -123,8 +125,7 @@ struct NodeParserData { void node_shader_materialx(void *data, struct bNode *node, struct bNodeSocket *out) \ { \ materialx::NodeParserData *d = reinterpret_cast(data); \ - d->result = MaterialXNodeParser( \ - d->graph, \ + d->result = MaterialXNodeParser(d->graph, \ d->depsgraph, \ d->material, \ node, \ -- 2.30.2 From d10771b96c974de868456cd6c07d19fa2344fe18 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Sun, 24 Sep 2023 13:51:48 +0300 Subject: [PATCH 35/40] Code adjustments after merge --- source/blender/nodes/shader/materialx/material.cc | 2 +- source/blender/nodes/shader/materialx/node_parser.h | 2 +- .../blender/nodes/shader/nodes/node_shader_tex_environment.cc | 2 +- source/blender/nodes/shader/nodes/node_shader_tex_image.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/shader/materialx/material.cc b/source/blender/nodes/shader/materialx/material.cc index 755c937ad74..65db8c68356 100644 --- a/source/blender/nodes/shader/materialx/material.cc +++ b/source/blender/nodes/shader/materialx/material.cc @@ -7,7 +7,7 @@ #include -#include "DEG_depsgraph.h" +#include "DEG_depsgraph.hh" #include "DNA_material_types.h" diff --git a/source/blender/nodes/shader/materialx/node_parser.h b/source/blender/nodes/shader/materialx/node_parser.h index 83a09aa5b76..125a391dcbc 100644 --- a/source/blender/nodes/shader/materialx/node_parser.h +++ b/source/blender/nodes/shader/materialx/node_parser.h @@ -6,7 +6,7 @@ #include "node_item.h" -#include "DEG_depsgraph.h" +#include "DEG_depsgraph.hh" #include "DNA_material_types.h" #include "DNA_node_types.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index feaa0351d0b..5ba951a342b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -11,7 +11,7 @@ #include "IMB_colormanagement.h" -#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph_query.hh" namespace blender::nodes::node_shader_tex_environment_cc { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index c81dbd6cf6b..bc84d5aa917 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -11,7 +11,7 @@ #include "IMB_colormanagement.h" -#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph_query.hh" namespace blender::nodes::node_shader_tex_image_cc { -- 2.30.2 From cf762804bc2c307b4e8f51115b7268fd8b446722 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 25 Sep 2023 18:12:47 +0200 Subject: [PATCH 36/40] Fix compiler errors and warnigs on Linux --- source/blender/nodes/shader/materialx/group_nodes.cc | 3 +++ source/blender/nodes/shader/nodes/node_shader_blackbody.cc | 3 ++- source/blender/nodes/shader/nodes/node_shader_color_ramp.cc | 3 ++- source/blender/nodes/shader/nodes/node_shader_light_path.cc | 3 ++- source/blender/nodes/shader/nodes/node_shader_uvmap.cc | 3 ++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/shader/materialx/group_nodes.cc b/source/blender/nodes/shader/materialx/group_nodes.cc index dac98d674da..4fbeefc4ce5 100644 --- a/source/blender/nodes/shader/materialx/group_nodes.cc +++ b/source/blender/nodes/shader/materialx/group_nodes.cc @@ -7,6 +7,9 @@ #include "BLI_vector.hh" +#include "BKE_node.h" +#include "BKE_node_runtime.hh" + namespace blender::nodes::materialx { GroupNodeParser::GroupNodeParser(MaterialX::GraphElement *graph, diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc index d88ae1d5d54..915ee52d310 100644 --- a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc +++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc @@ -42,7 +42,8 @@ NODE_SHADER_MATERIALX_BEGIN * NodeItem res = create_node("blackbody", NodeItem::Type::Color3); * res.set_input("temperature", temperature); * return res; */ - return empty(); + NodeItem res = empty(); + return res; } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc index 1f4aace65c3..a937dd3d0fc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -140,7 +140,8 @@ NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { /* TODO: Implement */ - return empty(); + NodeItem res = empty(); + return res; } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.cc b/source/blender/nodes/shader/nodes/node_shader_light_path.cc index 654688190dc..b29c9ea60ad 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_path.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc @@ -42,7 +42,8 @@ NODE_SHADER_MATERIALX_BEGIN if (STREQ(socket_out_->name, "Ray Length")) { return val(1.0f); } - return val(0.0f); + NodeItem res = val(0.0f); + return res; } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc index 9058dd00bf3..87e36f0581b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc @@ -73,7 +73,8 @@ NODE_SHADER_MATERIALX_BEGIN /* NODE: "From Instances" not implemented * UV selection not implemented */ - return texcoord_node(); + NodeItem res = texcoord_node(); + return res; } #endif NODE_SHADER_MATERIALX_END -- 2.30.2 From c2b5dfc2fe8874792bda52ebd40d07fc34714880 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 25 Sep 2023 20:36:48 +0200 Subject: [PATCH 37/40] Update for renamed Principled BSDF sockets --- .../shader/nodes/node_shader_bsdf_principled.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index c3e5e293150..933f4094877 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -330,26 +330,26 @@ NODE_SHADER_MATERIALX_BEGIN auto bsdf_inputs = [&]() -> InputsType { return { {"base_color", get_input_value("Base Color", NodeItem::Type::Color3)}, - {"subsurface", get_input_value("Subsurface", NodeItem::Type::Float)}, + {"subsurface", get_input_value("Subsurface Weight", NodeItem::Type::Float)}, {"subsurface_scale", get_input_value("Subsurface Scale", NodeItem::Type::Float)}, {"subsurface_radius", get_input_value("Subsurface Radius", NodeItem::Type::Vector3)}, //{"subsurface_ior", get_input_value("Subsurface IOR", NodeItem::Type::Vector3)}, {"subsurface_anisotropy", get_input_value("Subsurface Anisotropy", NodeItem::Type::Float)}, {"metallic", get_input_value("Metallic", NodeItem::Type::Float)}, - {"specular", get_input_value("Specular", NodeItem::Type::Float)}, + {"specular", get_input_value("Specular IOR Level", NodeItem::Type::Float)}, {"specular_tint", get_input_value("Specular Tint", NodeItem::Type::Color3)}, {"roughness", get_input_value("Roughness", NodeItem::Type::Float)}, {"anisotropic", get_input_value("Anisotropic", NodeItem::Type::Float)}, {"anisotropic_rotation", get_input_value("Anisotropic Rotation", NodeItem::Type::Float)}, - {"sheen", get_input_value("Sheen", NodeItem::Type::Float)}, + {"sheen", get_input_value("Sheen Weight", NodeItem::Type::Float)}, {"sheen_roughness", get_input_value("Sheen Roughness", NodeItem::Type::Float)}, {"sheen_tint", get_input_value("Sheen Tint", NodeItem::Type::Color3)}, - {"coat", get_input_value("Coat", NodeItem::Type::Float)}, + {"coat", get_input_value("Coat Weight", NodeItem::Type::Float)}, {"coat_roughness", get_input_value("Coat Roughness", NodeItem::Type::Float)}, {"coat_ior", get_input_value("Coat IOR", NodeItem::Type::Float)}, {"coat_tint", get_input_value("Coat Tint", NodeItem::Type::Color3)}, {"ior", get_input_value("IOR", NodeItem::Type::Float)}, - {"transmission", get_input_value("Transmission", NodeItem::Type::Float)}, + {"transmission", get_input_value("Transmission Weight", NodeItem::Type::Float)}, //{"alpha", get_input_value("Alpha", NodeItem::Type::Float)}, {"normal", get_input_link("Normal", NodeItem::Type::Vector3)}, {"coat_normal", get_input_link("Coat Normal", NodeItem::Type::Vector3)}, @@ -360,7 +360,7 @@ NODE_SHADER_MATERIALX_BEGIN 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 Color", NodeItem::Type::Color3)}, }; }; -- 2.30.2 From 2df0bc367082366feb40bcbef3467efebce0b3d2 Mon Sep 17 00:00:00 2001 From: "georgiy.m.markelov@gmail.com" Date: Tue, 26 Sep 2023 07:28:40 +0200 Subject: [PATCH 38/40] MaterialX: code improvements ### Purpose Code improvements ### Technical Steps Comments fixes `PrinsipleBSDF`: `subsurface_radius` type `Vector3` -> `Color3` Pull Request: https://projects.blender.org/DagerD/blender/pulls/34 --- .../nodes/shader/nodes/node_shader_bevel.cc | 2 +- .../nodes/node_shader_bsdf_principled.cc | 68 ++++++++++--------- .../shader/nodes/node_shader_geometry.cc | 2 +- .../shader/nodes/node_shader_light_path.cc | 2 +- .../shader/nodes/node_shader_object_info.cc | 2 +- .../shader/nodes/node_shader_particle_info.cc | 2 +- .../shader/nodes/node_shader_point_info.cc | 2 +- .../shader/nodes/node_shader_tex_coord.cc | 2 +- .../shader/nodes/node_shader_tex_noise.cc | 1 + .../shader/nodes/node_shader_wireframe.cc | 2 +- 10 files changed, 44 insertions(+), 41 deletions(-) diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.cc b/source/blender/nodes/shader/nodes/node_shader_bevel.cc index b17495bcb58..a495fca3dab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bevel.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc @@ -42,7 +42,7 @@ static int gpu_shader_bevel(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: This node doesn't have an implementation in MaterialX.*/ + /* NOTE: This node isn't supported by MaterialX.*/ return get_input_link("Normal", NodeItem::Type::Vector3); } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index 933f4094877..18b8bba388f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -538,39 +538,41 @@ NODE_SHADER_MATERIALX_BEGIN 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"]}}); + 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"]).convert(NodeItem::Type::Color3)}, + {"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: diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.cc b/source/blender/nodes/shader/nodes/node_shader_geometry.cc index 6d916b39f7b..a683a71d85f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.cc +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc @@ -61,7 +61,7 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: Some outputs don't have an implementation in MaterialX.*/ + /* NOTE: Some outputs aren't supported by MaterialX.*/ NodeItem res = empty(); std::string name = socket_out_->name; diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.cc b/source/blender/nodes/shader/nodes/node_shader_light_path.cc index b29c9ea60ad..63b0e20bd9b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_path.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc @@ -35,7 +35,7 @@ static int node_shader_gpu_light_path(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* This node isn't supported by MaterialX. Only default values returned. */ + /* NOTE: This node isn't supported by MaterialX. Only default values returned. */ if (STREQ(socket_out_->name, "Is Camera Ray")) { return val(1.0f); } diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.cc b/source/blender/nodes/shader/nodes/node_shader_object_info.cc index 5326d2d73fb..3bbab903042 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc @@ -33,7 +33,7 @@ static int node_shader_gpu_object_info(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: Some outputs don't have an implementation in MaterialX.*/ + /* NOTE: Some outputs isn't supported by MaterialX.*/ NodeItem res = empty(); std::string name = socket_out_->name; diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc index d194fb56769..69391fc73ba 100644 --- a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc @@ -37,7 +37,7 @@ static int gpu_shader_particle_info(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: This node doesn't have an implementation in MaterialX.*/ + /* NOTE: This node isn't supported by MaterialX.*/ return get_output_default(socket_out_->name, NodeItem::Type::Any); } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_point_info.cc b/source/blender/nodes/shader/nodes/node_shader_point_info.cc index 69ce2c94006..bc2b9611e0a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_point_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_point_info.cc @@ -25,7 +25,7 @@ static int node_shader_gpu_point_info(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: This node doesn't have an implementation in MaterialX.*/ + /* NOTE: This node isn't supported by MaterialX.*/ return get_output_default(socket_out_->name, NodeItem::Type::Any); } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc index c8e508937ee..dfc56d14d91 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc @@ -74,7 +74,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: Some outputs don't have an implementation in MaterialX.*/ + /* NOTE: Some outputs aren't supported by MaterialX.*/ NodeItem res = empty(); std::string name = socket_out_->name; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index 876e072e97d..1771ef14041 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -260,6 +260,7 @@ static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { + /* NOTE: Some inputs aren't supported by MaterialX.*/ NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); NodeItem detail = get_input_default("Detail", NodeItem::Type::Float); NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float); diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc index de80829b3fe..c9e7da17014 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc +++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc @@ -43,7 +43,7 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* NOTE: This node doesn't have an implementation in MaterialX.*/ + /* NOTE: This node isn't supported by MaterialX.*/ return get_output_default(socket_out_->name, NodeItem::Type::Float); } #endif -- 2.30.2 From 2e741c6825ed3e73d56266859a750e00964ff2de Mon Sep 17 00:00:00 2001 From: Vasyl-Pidhirskyi Date: Tue, 26 Sep 2023 11:02:14 +0200 Subject: [PATCH 39/40] MaterialX: code improvements shader modes. ### Purpose * Code improvements. * Implemente Tangent Node. * Glass shader is over-reflected, make Glass shader node utilize only `dielectric_bsdf` with Reflection and Transmission components (scatter = RT). `"""dielectric_bsdf: A reflection/transmission BSDF node based on a microfacet model and a Fresnel curve for dielectrics."""` * Sheen node `Roughness` input affects the node's effect. ### Technical Steps * Code Improvements. * Comments fixes. * Implemented Tangent Node, using default `tangent` node. * Glass shader node: removed mixing with `conductor_bsdf` node as far as `dielectric_bsdf` node already has a reflection component so `conductor_bsdf` seems redundant. * Sheen node: removed `weight` input for `sheen_bsdf`, as far as it affects the node's effect. * Renamed Displacementshader -> DisplacementShader. Pull Request: https://projects.blender.org/DagerD/blender/pulls/35 --- .../nodes/shader/materialx/node_item.cc | 17 ++++++----- .../nodes/shader/materialx/node_item.h | 2 +- .../shader/nodes/node_shader_bsdf_glass.cc | 30 +++++-------------- .../shader/nodes/node_shader_bsdf_sheen.cc | 7 ++--- .../shader/nodes/node_shader_displacement.cc | 2 +- .../nodes/shader/nodes/node_shader_tangent.cc | 4 +-- .../nodes/node_shader_vector_displacement.cc | 2 +- 7 files changed, 24 insertions(+), 40 deletions(-) diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index d65332fdb02..453aa6ed5b3 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -54,7 +54,7 @@ NodeItem::Type NodeItem::type(const std::string &type_str) return Type::EDF; } if (type_str == "displacementshader") { - return Type::Displacementshader; + return Type::DisplacementShader; } if (type_str == "surfaceshader") { return Type::SurfaceShader; @@ -97,7 +97,7 @@ std::string NodeItem::type(Type type) return "BSDF"; case Type::EDF: return "EDF"; - case Type::Displacementshader: + case Type::DisplacementShader: return "displacementshader"; case Type::SurfaceShader: return "surfaceshader"; @@ -388,14 +388,15 @@ NodeItem NodeItem::rotate(const NodeItem &angle_xyz, bool invert) NodeItem x = angle_xyz[0]; NodeItem y = angle_xyz[1]; NodeItem z = angle_xyz[2]; + + NodeItem x_axis = val(MaterialX::Vector3(1.0f, 0.0f, 0.0f)); + NodeItem y_axis = val(MaterialX::Vector3(0.0f, 1.0f, 0.0f)); + NodeItem z_axis = val(MaterialX::Vector3(0.0f, 0.0f, 1.0f)); + 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(z, z_axis).rotate(y, y_axis).rotate(x, x_axis); } - 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))); + return rotate(x, x_axis).rotate(y, y_axis).rotate(z, z_axis); } NodeItem NodeItem::sin() const diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index 0b6069c406a..92396952055 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -41,7 +41,7 @@ class NodeItem { /* Shader types. NOTE: There are only supported types */ BSDF, EDF, - Displacementshader, + DisplacementShader, SurfaceShader, Material, }; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index 37b850ab253..ef2b8308c83 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -54,29 +54,13 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem ior = get_input_value("IOR", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - NodeItem dielectric = create_node("dielectric_bsdf", - NodeItem::Type::BSDF, - {{"normal", normal}, - {"tint", color}, - {"roughness", roughness}, - {"ior", ior}, - {"scatter_mode", val(std::string("RT"))}}); - - NodeItem artistic_ior = create_node("artistic_ior", - NodeItem::Type::Multioutput, - {{"reflectivity", color}, {"edge_color", color}}); - NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3); - NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3); - - NodeItem conductor = create_node("conductor_bsdf", - NodeItem::Type::BSDF, - {{"normal", normal}, - {"ior", ior_out}, - {"extinction", extinction_out}, - {"roughness", roughness}}); - - return create_node( - "mix", NodeItem::Type::BSDF, {{"fg", dielectric}, {"bg", conductor}, {"mix", val(0.5f)}}); + return create_node("dielectric_bsdf", + NodeItem::Type::BSDF, + {{"normal", normal}, + {"tint", color}, + {"roughness", roughness}, + {"ior", ior}, + {"scatter_mode", val(std::string("RT"))}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc index 59469c8abb3..0beee3c1e37 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_sheen.cc @@ -58,10 +58,9 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float); NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3); - return create_node( - "sheen_bsdf", - NodeItem::Type::BSDF, - {{"color", color}, {"weight", roughness}, {"roughness", roughness}, {"normal", normal}}); + return create_node("sheen_bsdf", + NodeItem::Type::BSDF, + {{"color", color}, {"roughness", roughness}, {"normal", normal}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_displacement.cc index 2083e7eed77..db6d8b4969b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_displacement.cc +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc @@ -46,7 +46,7 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); return create_node("displacement", - NodeItem::Type::Displacementshader, + NodeItem::Type::DisplacementShader, {{"displacement", height}, {"scale", scale}}); } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.cc b/source/blender/nodes/shader/nodes/node_shader_tangent.cc index 69403f9293a..eda4c94cabb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tangent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc @@ -89,8 +89,8 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - /* TODO: This node doesn't have an implementation in MaterialX.*/ - return get_output_default(socket_out_->name, NodeItem::Type::Vector3); + /* TODO: implement other features */ + return create_node("tangent", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}}); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc index 8d0a87ad17d..acf48eddb33 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc @@ -50,7 +50,7 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); return create_node("displacement", - NodeItem::Type::Displacementshader, + NodeItem::Type::DisplacementShader, {{"displacement", vector}, {"scale", scale}}); } #endif -- 2.30.2 From 6e1775d516909acc6448267e83965a5482439954 Mon Sep 17 00:00:00 2001 From: Bogdan Nagirniak Date: Tue, 26 Sep 2023 16:16:08 +0200 Subject: [PATCH 40/40] Implement BSDF Transparent shader ### Purpose Implement BSDF Transparent + include and shader's opacity to MatX nodetree. ### Technical steps 1. Added special type `NodeItem::Type::SurfaceOpacity` to retrieve opacity for \ node. 2. Implemented export of BSDFTransparent node. 3. Implemented export of opacity component in BSDFPrincipled, Add/Mix shader nodes. 4. Removed redundant code. ### Notes Storm and RPR hydra delegates aren't working good with opacity, this has to be fixed on delegate/hydra side, therefore those changes won't be visible. Opacity can be checked in MaterialXView or MaterialXGraphEditor of the exported mtlx. Pull Request: https://projects.blender.org/DagerD/blender/pulls/36 --- .../nodes/shader/materialx/node_item.cc | 3 +++ .../nodes/shader/materialx/node_item.h | 3 +++ .../nodes/shader/materialx/node_parser.cc | 2 +- .../shader/nodes/node_shader_add_shader.cc | 5 +++- .../nodes/node_shader_bsdf_principled.cc | 14 +++++++---- .../nodes/node_shader_bsdf_transparent.cc | 23 +++++++++++++++++++ .../shader/nodes/node_shader_light_falloff.cc | 2 +- .../shader/nodes/node_shader_mix_shader.cc | 2 +- .../nodes/node_shader_output_material.cc | 11 ++++----- 9 files changed, 49 insertions(+), 16 deletions(-) diff --git a/source/blender/nodes/shader/materialx/node_item.cc b/source/blender/nodes/shader/materialx/node_item.cc index 453aa6ed5b3..5cc1c32db29 100644 --- a/source/blender/nodes/shader/materialx/node_item.cc +++ b/source/blender/nodes/shader/materialx/node_item.cc @@ -14,6 +14,7 @@ NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} NodeItem::Type NodeItem::type(const std::string &type_str) { + /* Converting only MaterialX supported types */ if (type_str == "multioutput") { return Type::Multioutput; } @@ -103,6 +104,8 @@ std::string NodeItem::type(Type type) return "surfaceshader"; case Type::Material: return "material"; + case Type::SurfaceOpacity: + return "opacity"; default: BLI_assert_unreachable(); } diff --git a/source/blender/nodes/shader/materialx/node_item.h b/source/blender/nodes/shader/materialx/node_item.h index 92396952055..8e4ea259a3a 100644 --- a/source/blender/nodes/shader/materialx/node_item.h +++ b/source/blender/nodes/shader/materialx/node_item.h @@ -44,6 +44,9 @@ class NodeItem { DisplacementShader, SurfaceShader, Material, + + /* Special type to retrieve opacity for */ + SurfaceOpacity, }; enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq }; diff --git a/source/blender/nodes/shader/materialx/node_parser.cc b/source/blender/nodes/shader/materialx/node_parser.cc index beedcab3471..eeb7ae88320 100644 --- a/source/blender/nodes/shader/materialx/node_parser.cc +++ b/source/blender/nodes/shader/materialx/node_parser.cc @@ -64,7 +64,7 @@ std::string NodeParser::node_name() const if (node_->output_sockets().size() > 1) { name += std::string("_") + socket_out_->name; } - if (ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { + if (ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF, NodeItem::Type::SurfaceOpacity)) { name += "_" + NodeItem::type(to_type_); } #ifdef USE_MATERIALX_NODEGRAPH diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc index 6e0e0a81a51..13e76464437 100644 --- a/source/blender/nodes/shader/nodes/node_shader_add_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc @@ -25,7 +25,7 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { + if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF, NodeItem::Type::SurfaceOpacity)) { return empty(); } @@ -41,6 +41,9 @@ NODE_SHADER_MATERIALX_BEGIN if (!shader1 && shader2) { return shader2; } + if (to_type_ == NodeItem::Type::SurfaceOpacity) { + return (shader1 + shader2) * val(0.5f); + } return shader1 + shader2; } #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index 18b8bba388f..865df5b1fe6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -350,7 +350,7 @@ NODE_SHADER_MATERIALX_BEGIN {"coat_tint", get_input_value("Coat Tint", NodeItem::Type::Color3)}, {"ior", get_input_value("IOR", NodeItem::Type::Float)}, {"transmission", get_input_value("Transmission Weight", NodeItem::Type::Float)}, - //{"alpha", get_input_value("Alpha", NodeItem::Type::Float)}, + {"alpha", get_input_value("Alpha", NodeItem::Type::Float)}, {"normal", get_input_link("Normal", NodeItem::Type::Vector3)}, {"coat_normal", get_input_link("Coat Normal", NodeItem::Type::Vector3)}, {"tangent", get_input_link("Tangent", NodeItem::Type::Vector3)}, @@ -509,9 +509,6 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem n_thin_film_layer = create_node( "layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}}); - NodeItem n_opacity_luminance = create_node( - "luminance", NodeItem::Type::Color3, {{"in", val(MaterialX::Color3(1.0f, 1.0f, 1.0f))}}); - NodeItem n_coat_attenuation = coat.mix(val(MaterialX::Color3(1.0f, 1.0f, 1.0f)), in["coat_tint"]); @@ -572,9 +569,16 @@ NODE_SHADER_MATERIALX_BEGIN {"emission", in["emission"]}, {"emission_color", in["emission_color"]}, {"normal", in["normal"]}, - {"tangent", in["tangent"]}}); + {"tangent", in["tangent"]}, + {"opacity", in["alpha"].convert(NodeItem::Type::Color3)}}); break; } + + case NodeItem::Type::SurfaceOpacity: { + res = get_input_value("Alpha", NodeItem::Type::Float); + break; + } + default: BLI_assert_unreachable(); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc index 5de21efe791..bf71cbe232f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc @@ -27,6 +27,28 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out); } +NODE_SHADER_MATERIALX_BEGIN +#ifdef WITH_MATERIALX +{ + switch (to_type_) { + case NodeItem::Type::BSDF: { + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + /* Returning diffuse node as BSDF component */ + return create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF, {{"color", color}}); + } + case NodeItem::Type::SurfaceOpacity: { + NodeItem color = get_input_value("Color", NodeItem::Type::Color3); + /* Returning: 1 - */ + return val(1.0f) - color.dotproduct(val(1.0f / 3.0f)); + } + default: + break; + } + return empty(); +} +#endif +NODE_SHADER_MATERIALX_END + } // namespace blender::nodes::node_shader_bsdf_transparent_cc /* node type definition */ @@ -40,6 +62,7 @@ void register_node_type_sh_bsdf_transparent() ntype.add_ui_poll = object_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_transparent; + ntype.materialx_fn = file_ns::node_shader_materialx; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc index bd5db49387f..ba77c71673b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc +++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc @@ -32,7 +32,7 @@ NODE_SHADER_MATERIALX_BEGIN /* This node isn't supported by MaterialX. This formula was given from OSL shader code in Cycles * node_light_falloff.osl. Considered ray_length=1.0f. */ - return strength * val(1.0f) / (smooth + val(1.0f)); + return strength / (smooth + val(1.0f)); } #endif NODE_SHADER_MATERIALX_END diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index 249d4f85c7a..f73efb8394a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -26,7 +26,7 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat, NODE_SHADER_MATERIALX_BEGIN #ifdef WITH_MATERIALX { - if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF)) { + if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF, NodeItem::Type::SurfaceOpacity)) { return empty(); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index b405c40e8af..9995292c9a0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -51,13 +51,10 @@ NODE_SHADER_MATERIALX_BEGIN NodeItem bsdf = get_input_link("Surface", NodeItem::Type::BSDF); NodeItem edf = get_input_link("Surface", NodeItem::Type::EDF); if (bsdf || edf) { - surface = create_node("surface", NodeItem::Type::SurfaceShader); - if (bsdf) { - surface.set_input("bsdf", bsdf); - } - if (edf) { - surface.set_input("edf", edf); - } + NodeItem opacity = get_input_link("Surface", NodeItem::Type::SurfaceOpacity); + surface = create_node("surface", + NodeItem::Type::SurfaceShader, + {{"bsdf", bsdf}, {"edf", edf}, {"opacity", opacity}}); } } return create_node("surfacematerial", NodeItem::Type::Material, {{"surfaceshader", surface}}); -- 2.30.2