diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 0806cd355107..d913410f8341 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 157db1e9ab74..424fd7aba799 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 fa2c698146b5..dca349b2b009 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 a1113ec311fa..1888021af16c 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 f27be0ac29c8..8e3350199e85 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 000000000000..e00bbce4d598 --- /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 000000000000..b4cace6d8216 --- /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 f7f192ace407..000000000000 --- 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 fc83f8b3e4a7..000000000000 --- 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 541e58bd7bd7..000000000000 --- 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 8ffda3d00d94..000000000000 --- 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 5b6b18ca011a..000000000000 --- 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 3f95c16ae233..000000000000 --- 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 000000000000..11da5c8158a7 --- /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 000000000000..5a021e8bb33f --- /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 000000000000..6b3a4584ec53 --- /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 000000000000..0701c0769e8a --- /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 c410dc1378d6..000000000000 --- 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 6b699f9ef3df..000000000000 --- 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 000000000000..3d1a0423c9fa --- /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 000000000000..cc6f962ef88a --- /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 82f3c3172d84..5bf5dc653fbc 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); }