Files
test/source/blender/nodes/shader/materialx/node_parser.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

124 lines
3.8 KiB
C
Raw Normal View History

/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
USD: Add MaterialX shader export This change adds the ability to export MaterialX networks into the resulting USD layer. Details: A new export option has been added to the USD export to enable MaterialX export. It is off by default currently due to reasons in the caveats section. When enabled, it exports the MaterialX shading network alongside the UsdPreviewSurface network, on the same USD Material. This allows the same material to be used by renderers that don't support MaterialX, using the USDPreviewSurface as a fallback. This is similar to setups in other DCC packages, and matches the format we've used in our Reality Composer Pro asset library. It uses the existing MaterialX framework used to generate MaterialX documents for rendering, to act as the basis for the USD graph. In this process it also re-uses the existing texture export code as well if provided and necessary. Once the MaterialX document is created, use usdMtlx to generate a USD shading network. Unfortunately, usdMtlx generates a graph that is unlike what other DCCs that support MaterialX-embedded-in-USD generates. It generates several extra prim hierarchies, and externalizes all shader inputs, making them difficult to edit in other MaterialX graph editors. To workaround this, generate the MaterialX shading network onto a temporary stage, where we then run various pre-processing steps to prevent prim collisions and to reflow the paths once they're converted. The PrimSpecs are then copied over to their new path. The resulting prim hierarchy matches what many artists we've worked with prefer to work with. Caveats: The Export MaterialX check is off by default. When using the Principled BSDF, the resulting graph is very usable. However, when using some of the other BSDFs, the shading networks generated by the existing MaterialX framework in Blender generate some shading graphs that are difficult for usdview and other DCC's to understand. The graph is still correct, but because we're trying to prioritize compatibility, the default is off. In future PRs we can aim to make the graphs for those other BSDFs play better with other DCCs. Other Implementation Details: As part of this commit we've also done the following: * Place some of the materialx graphs inside a passthrough nodegraph to avoid node conflicts. * Better handle some shader output types , and better handle some conflict cases. * Moved the ExportTextureFunction to materials.h due to some difficult to resolve header ordering issues. This has no effect on any runtime code. * There is a test for the MaterialX export that does some basic checking to make sure we get an export out the other end that matches our expectations Authored by Apple: Dhruv Govil This PR is based on an earlier implementation by Brecht van Lommel , as well as Brian Savery and his teams' work at AMD to implement the general MaterialX framework within Blender. Pull Request: https://projects.blender.org/blender/blender/pulls/122575
2024-06-05 20:43:44 +02:00
#include "material.h"
#include "node_graph.h"
#include "node_item.h"
#include "DNA_node_types.h"
#include "CLG_log.h"
namespace blender::nodes::materialx {
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
class GroupNodeParser;
/**
* This is base abstraction class for parsing Blender nodes into MaterialX nodes.
2023-09-27 13:02:37 +10:00
* #NodeParser::compute() should be overridden in child classes.
*/
class NodeParser {
protected:
NodeGraph &graph_;
const bNode *node_;
const bNodeSocket *socket_out_;
NodeItem::Type to_type_;
GroupNodeParser *group_parser_;
public:
NodeParser(NodeGraph &graph,
const bNode *node,
const bNodeSocket *socket_out,
NodeItem::Type to_type,
GroupNodeParser *group_parser);
virtual ~NodeParser() = default;
virtual NodeItem compute() = 0;
virtual NodeItem compute_full();
protected:
std::string node_name(const char *override_output_name = nullptr) 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);
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);
NodeItem get_input_value(int index, NodeItem::Type to_type);
NodeItem empty() const;
template<class T> NodeItem val(const T &data) const;
NodeItem texcoord_node(NodeItem::Type type = NodeItem::Type::Vector2,
const std::string &attribute_name = "");
private:
NodeItem get_default(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);
};
template<class T> NodeItem NodeParser::val(const T &data) const
{
return empty().val(data);
}
/**
* Defines for including MaterialX node parsing code into node_shader_<name>.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 {
NodeGraph &graph;
NodeItem::Type to_type;
GroupNodeParser *group_parser;
NodeItem result;
ExportParams export_params;
};
#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 \
} \
\
static void node_shader_materialx(void *data, struct bNode *node, struct bNodeSocket *out) \
{ \
materialx::NodeParserData *d = reinterpret_cast<materialx::NodeParserData *>(data); \
d->result = \
MaterialXNodeParser(d->graph, node, out, d->to_type, d->group_parser).compute_full(); \
}
} // namespace blender::nodes::materialx