Create parsing system that converts supported nodes and ignores unsupported #2

Merged
Bogdan Nagirniak merged 14 commits from Vasyl-Pidhirskyi/blender:BLEN-500 into matx-export-material 2023-08-28 12:29:46 +02:00
22 changed files with 550 additions and 344 deletions

View File

@ -209,6 +209,10 @@ if(WITH_OPENVDB)
) )
endif() endif()
if(WITH_MATERIALX)
list(APPEND LIB MaterialXCore)
endif()
blender_add_lib(bf_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") blender_add_lib(bf_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
# RNA_prototypes.h # RNA_prototypes.h

View File

@ -52,7 +52,9 @@ class HydraSceneDelegate : public pxr::HdSceneDelegate {
const View3D *view3d = nullptr; const View3D *view3d = nullptr;
Main *bmain = nullptr; Main *bmain = nullptr;
Scene *scene = nullptr; Scene *scene = nullptr;
ShadingSettings shading_settings; ShadingSettings shading_settings;
bool use_materialx = true;
private: private:
ObjectDataMap objects_; ObjectDataMap objects_;

View File

@ -12,6 +12,9 @@
#include <pxr/imaging/hd/tokens.h> #include <pxr/imaging/hd/tokens.h>
#include <pxr/usdImaging/usdImaging/materialParamUtils.h> #include <pxr/usdImaging/usdImaging/materialParamUtils.h>
#include <pxr/usd/usdMtlx/reader.h>
#include <pxr/usd/usdMtlx/utils.h>
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
@ -30,6 +33,7 @@
#include "intern/usd_exporter_context.h" #include "intern/usd_exporter_context.h"
#include "intern/usd_writer_material.h" #include "intern/usd_writer_material.h"
#include "shader/materialx/material.h"
namespace blender::io::hydra { namespace blender::io::hydra {
@ -66,10 +70,22 @@ void MaterialData::init()
time, time,
export_params, export_params,
image_cache_file_path()}; image_cache_file_path()};
/* Create USD material. */ /* Create USD material. */
pxr::UsdShadeMaterial usd_material = usd::create_usd_material( pxr::UsdShadeMaterial usd_material;
export_context, material_path, (Material *)id, "st"); 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. */ /* Convert USD material to Hydra material network map, adapted for render delegate. */
const pxr::HdRenderDelegate *render_delegate = const pxr::HdRenderDelegate *render_delegate =

View File

@ -145,18 +145,19 @@ set(LIB
if(WITH_MATERIALX) if(WITH_MATERIALX)
list(APPEND LIB MaterialXCore) list(APPEND LIB MaterialXCore)
list(APPEND LIB MaterialXFormat)
list(APPEND SRC list(APPEND SRC
materialx/material.cc materialx/material.cc
materialx/nodes/node.cc materialx/nodes/bsdf_principled.cc
materialx/nodes/material_output.cc materialx/nodes/node_parser.cc
materialx/nodes/principled_bsdf.cc materialx/nodes/output_material.cc
materialx/nodes/image.cc materialx/nodes/tex_image.cc
materialx/material.h materialx/material.h
materialx/nodes/node.h materialx/nodes/bsdf_principled.h
materialx/nodes/material_output.h materialx/nodes/node_parser.h
materialx/nodes/principled_bsdf.h materialx/nodes/output_material.h
materialx/nodes/image.h materialx/nodes/tex_image.h
) )
endif() endif()

View File

@ -3,34 +3,37 @@
* SPDX-License-Identifier: GPL-2.0-or-later */ * SPDX-License-Identifier: GPL-2.0-or-later */
#include "material.h" #include "material.h"
#include "nodes/material_output.h" #include "nodes/output_material.h"
#include <MaterialXCore/Node.h> #include <MaterialXCore/Node.h>
#include <MaterialXFormat/XmlIo.h>
#include "NOD_shader.h" #include "NOD_shader.h"
namespace blender::nodes::materialx { 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(); material->nodetree->ensure_topology_cache();
bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL);
MaterialXMaterialOutputNode material_node(doc, depsgraph, material, output_node); OutputMaterialNodeParser parser(graph, depsgraph, material, output_node);
material_node.convert(); 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( MaterialX::NodePtr standard_surface = graph->addNode(
"surfacematerial", MaterialX::EMPTY_STRING, "material");
MaterialX::NodePtr standard_surface = doc->addNode(
"standard_surface", MaterialX::EMPTY_STRING, "surfaceshader"); "standard_surface", MaterialX::EMPTY_STRING, "surfaceshader");
standard_surface->addInput("base", "float")->setValue(1.0); standard_surface->addInput("base", "float")->setValue(1.0);
standard_surface->addInput("base_color", "color3") standard_surface->addInput("base_color", "color3")
->setValue(MaterialX::Color3(material->r, material->g, material->b)); ->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()) surfacematerial->addInput(standard_surface->getType(), standard_surface->getType())
->setNodeName(standard_surface->getName()); ->setNodeName(standard_surface->getName());
} }
@ -39,11 +42,13 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater
{ {
MaterialX::DocumentPtr doc = MaterialX::createDocument(); MaterialX::DocumentPtr doc = MaterialX::createDocument();
if (material->use_nodes) { if (material->use_nodes) {
export_nodegraph(doc, depsgraph, material); export_nodegraph(doc.get(), depsgraph, material);
} }
else { 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; return doc;
} }

View File

@ -0,0 +1,145 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "bsdf_principled.h"
#include <BKE_node_runtime.hh>
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<float>()) {
return val.value->asA<float>() != 0.0f;
}
if (val.value->isA<MaterialX::Color4>()) {
auto c = val.value->asA<MaterialX::Color4>();
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

View File

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

View File

@ -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<NodeTexImage *>(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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,33 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <MaterialXCore/Document.h>
#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

View File

@ -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 <BKE_node_runtime.hh>
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<float>()) {
set_input(name, value->asA<float>(), "float");
}
else if (value->isA<MaterialX::Vector3>()) {
set_input(name, value->asA<MaterialX::Vector3>(), "vector3");
}
else if (value->isA<MaterialX::Vector4>()) {
set_input(name, value->asA<MaterialX::Vector4>(), "vector4");
}
else if (value->isA<MaterialX::Color3>()) {
set_input(name, value->asA<MaterialX::Color3>(), "color3");
}
else if (value->isA<MaterialX::Color4>()) {
set_input(name, value->asA<MaterialX::Color4>(), "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>()) {
float v = value->asA<float>();
res.value = MaterialX::Value::createValue<MaterialX::Color3>(MaterialX::Color3(v, v, v));
}
else if (value->isA<MaterialX::Color3>()) {
res.value = value;
}
else if (value->isA<MaterialX::Color4>()) {
auto c = value->asA<MaterialX::Color4>();
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
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<bNodeSocketValueFloat>()->value;
res.value = MaterialX::Value::createValue<float>(v);
} break;
case SOCK_VECTOR: {
const float *v = socket.default_value_typed<bNodeSocketValueVector>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
MaterialX::Vector3(v[0], v[1], v[2]));
} break;
case SOCK_RGBA: {
const float *v = socket.default_value_typed<bNodeSocketValueRGBA>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
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<NodeParser> parser;
switch (in_node->type) {
case SH_NODE_BSDF_PRINCIPLED:
parser = std::make_unique<BSDFPrincipledNodeParser>(graph, depsgraph, material, in_node);
break;
case SH_NODE_TEX_IMAGE:
parser = std::make_unique<TexImageNodeParser>(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

View File

@ -0,0 +1,70 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <MaterialXCore/Document.h>
#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<class T>
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<class T>
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

View File

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

View File

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

View File

@ -1,126 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "principled_bsdf.h"
#include <BKE_node_runtime.hh>
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<bNodeSocketValueRGBA>()->value;
const float subsurface =
node->input_by_identifier("Subsurface").default_value_typed<bNodeSocketValueFloat>()->value;
const float *subsurface_radius = node->input_by_identifier("Subsurface Radius")
.default_value_typed<bNodeSocketValueVector>()
->value;
const float *subsurface_color = node->input_by_identifier("Subsurface Color")
.default_value_typed<bNodeSocketValueRGBA>()
->value;
const float metallic =
node->input_by_identifier("Metallic").default_value_typed<bNodeSocketValueFloat>()->value;
const float specular =
node->input_by_identifier("Specular").default_value_typed<bNodeSocketValueFloat>()->value;
const float roughness =
node->input_by_identifier("Roughness").default_value_typed<bNodeSocketValueFloat>()->value;
const float anisotropic =
node->input_by_identifier("Anisotropic").default_value_typed<bNodeSocketValueFloat>()->value;
const float anisotropic_rot = node->input_by_identifier("Anisotropic Rotation")
.default_value_typed<bNodeSocketValueFloat>()
->value;
const float sheen =
node->input_by_identifier("Sheen").default_value_typed<bNodeSocketValueFloat>()->value;
const float clearcoat =
node->input_by_identifier("Clearcoat").default_value_typed<bNodeSocketValueFloat>()->value;
const float clearcoat_roughness = node->input_by_identifier("Clearcoat Roughness")
.default_value_typed<bNodeSocketValueFloat>()
->value;
const float IOR =
node->input_by_identifier("IOR").default_value_typed<bNodeSocketValueFloat>()->value;
const float transmission = node->input_by_identifier("Transmission")
.default_value_typed<bNodeSocketValueFloat>()
->value;
const float *emission =
node->input_by_identifier("Emission").default_value_typed<bNodeSocketValueRGBA>()->value;
const float emission_str = node->input_by_identifier("Emission Strength")
.default_value_typed<bNodeSocketValueFloat>()
->value;
const float *normal =
node->input_by_identifier("Normal").default_value_typed<bNodeSocketValueVector>()->value;
const float *clearcoat_normal = node->input_by_identifier("Clearcoat Normal")
.default_value_typed<bNodeSocketValueVector>()
->value;
const float *tangent =
node->input_by_identifier("Tangent").default_value_typed<bNodeSocketValueVector>()->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

View File

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

View File

@ -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<NodeTexImage *>(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

View File

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

View File

@ -89,6 +89,7 @@ void Engine::sync(Depsgraph *depsgraph, bContext *context)
pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"); pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene");
hydra_scene_delegate_ = std::make_unique<io::hydra::HydraSceneDelegate>(render_index_.get(), hydra_scene_delegate_ = std::make_unique<io::hydra::HydraSceneDelegate>(render_index_.get(),
scene_path); 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); hydra_scene_delegate_->populate(depsgraph, context ? CTX_wm_view3d(context) : nullptr);
} }