diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index c05bb53c9e17..eeebefeb73ae 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 9f8c497743ba..f27be0ac29c8 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 d0706153b679..1784c42349b7 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 000000000000..7faf20485e44 --- /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 000000000000..fc83f8b3e4a7 --- /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 000000000000..541e58bd7bd7 --- /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 000000000000..8ffda3d00d94 --- /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 000000000000..5b6b18ca011a --- /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 000000000000..3f95c16ae233 --- /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 000000000000..c410dc1378d6 --- /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 000000000000..6b699f9ef3df --- /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