Export material to MaterialX for Hydra render #111765
|
@ -225,6 +225,9 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
|
|||
struct bNodeExecData *execdata,
|
||||
struct GPUNodeStack *in,
|
||||
struct GPUNodeStack *out);
|
||||
typedef void (*NodeMaterialXFunction)(void *data,
|
||||
BogdanNagirniak marked this conversation as resolved
Outdated
|
||||
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 */
|
||||
NodeMaterialXFunction materialx_fn;
|
||||
|
||||
/* Get an instance of this node's compositor operation. Freeing the instance is the
|
||||
* responsibility of the caller. */
|
||||
|
|
|
@ -209,6 +209,11 @@ if(WITH_OPENVDB)
|
|||
)
|
||||
endif()
|
||||
|
||||
if(WITH_MATERIALX)
|
||||
add_definitions(-DWITH_MATERIALX)
|
||||
BogdanNagirniak marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
Add Add `add_definitions(-DWITH_MATERIALX)`
|
||||
list(APPEND LIB MaterialXCore)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_io_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
# RNA_prototypes.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_;
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include <pxr/imaging/hd/tokens.h>
|
||||
#include <pxr/usdImaging/usdImaging/materialParamUtils.h>
|
||||
|
||||
#ifdef WITH_MATERIALX
|
||||
BogdanNagirniak marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
Add Add `#ifdef WITH_MATERIALX` here and other places in this file, to make it possible to build without materialx.
|
||||
# include <pxr/usd/usdMtlx/reader.h>
|
||||
# include <pxr/usd/usdMtlx/utils.h>
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
|
@ -30,7 +35,10 @@
|
|||
|
||||
#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 {
|
||||
|
||||
MaterialData::MaterialData(HydraSceneDelegate *scene_delegate,
|
||||
|
@ -67,10 +75,35 @@ void MaterialData::init()
|
|||
get_time_code,
|
||||
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;
|
||||
#ifdef WITH_MATERIALX
|
||||
if (scene_delegate_->use_materialx) {
|
||||
MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx(
|
||||
scene_delegate_->depsgraph, (Material *)id, cache_or_get_image_file);
|
||||
pxr::UsdMtlxRead(doc, stage);
|
||||
|
||||
BogdanNagirniak marked this conversation as resolved
Brecht Van Lommel
commented
for not to -> to not for not to -> to not
|
||||
/* Logging stage: creating lambda stage_str() to not 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()) {
|
||||
usd_material = pxr::UsdShadeMaterial(*children.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
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 =
|
||||
|
|
|
@ -998,6 +998,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 MaterialX", "Use MaterialX for exporting materials to Hydra");
|
||||
|
||||
RNA_define_verify_sdna(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ set(INC
|
|||
../../makesrna
|
||||
../../render
|
||||
../../windowmanager
|
||||
../../../../intern/clog
|
||||
../../../../intern/sky/include
|
||||
# RNA_prototypes.h
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
|
@ -136,6 +137,25 @@ set(LIB
|
|||
bf_nodes
|
||||
)
|
||||
|
||||
if(WITH_MATERIALX)
|
||||
add_definitions(-DWITH_MATERIALX)
|
||||
list(APPEND SRC
|
||||
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
|
||||
MaterialXFormat
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/* 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"
|
||||
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_node_runtime.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();
|
||||
|
||||
const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(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<MaterialX::NodeGraph>(name);
|
||||
if (!group_graph) {
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "<nodegraph name=%s>", name.c_str());
|
||||
group_graph = graph_->addChild<MaterialX::NodeGraph>(name);
|
||||
}
|
||||
graph = group_graph.get();
|
||||
#endif
|
||||
|
||||
NodeItem out = GroupOutputNodeParser(graph,
|
||||
depsgraph_,
|
||||
material_,
|
||||
node_out,
|
||||
socket_out_,
|
||||
to_type_,
|
||||
this,
|
||||
export_image_fn_,
|
||||
use_group_default_)
|
||||
.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;
|
||||
}
|
||||
|
||||
BogdanNagirniak marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
Can you explain why this is using I guess it's not to avoid naming conflicts, because Can you explain why this is using `output + index` rather than output socket names?
I guess it's not to avoid naming conflicts, because `output1` isn't unique enough that a user would never name their socket like this.
Bogdan Nagirniak
commented
Changed name to Changed name to `out_<out socket name>`
|
||||
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<NodeItem> values;
|
||||
for (auto socket_in : node_->input_sockets()) {
|
||||
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}});
|
||||
}
|
||||
values.append(value);
|
||||
}
|
||||
Vector<NodeItem> outputs;
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
if (values[i]) {
|
||||
outputs.append(create_output(out_name(node_->input_sockets()[i]), values[i]));
|
||||
}
|
||||
}
|
||||
return outputs[socket_out_->index()];
|
||||
#else
|
||||
if (use_group_default_) {
|
||||
return get_input_value(socket_out_->index(), to_type_);
|
||||
}
|
||||
return get_input_link(socket_out_->index(), to_type_);
|
||||
#endif
|
||||
}
|
||||
|
||||
NodeItem GroupOutputNodeParser::compute_full()
|
||||
{
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER,
|
||||
1,
|
||||
"%s [%d] => %s",
|
||||
node_->name,
|
||||
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
|
||||
return compute();
|
||||
#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
|
||||
NodeItem value = group_parser_->get_input_link(socket_out_->index(), to_type_);
|
||||
if (!value) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
if (value.value) {
|
||||
value = group_parser_->create_node("constant", value.type(), {{"value", value}});
|
||||
}
|
||||
return create_input(in_name(), value);
|
||||
#else
|
||||
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_);
|
||||
#endif
|
||||
}
|
||||
|
||||
NodeItem GroupInputNodeParser::compute_full()
|
||||
{
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER,
|
||||
1,
|
||||
"%s [%d] => %s",
|
||||
node_->name,
|
||||
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
|
||||
return compute();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GroupInputNodeParser::in_name() const
|
||||
{
|
||||
return MaterialX::createValidName(std::string("in_") + socket_out_->name);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -0,0 +1,57 @@
|
|||
/* 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 GroupInputNodeParser;
|
||||
|
||||
protected:
|
||||
bool use_group_default_;
|
||||
|
||||
public:
|
||||
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 GroupNodeParser {
|
||||
public:
|
||||
using GroupNodeParser::GroupNodeParser;
|
||||
NodeItem compute() override;
|
||||
NodeItem compute_full() override;
|
||||
|
||||
private:
|
||||
static std::string out_name(const bNodeSocket *out_socket);
|
||||
};
|
||||
|
||||
class GroupInputNodeParser : public GroupNodeParser {
|
||||
public:
|
||||
using GroupNodeParser::GroupNodeParser;
|
||||
NodeItem compute() override;
|
||||
NodeItem compute_full() override;
|
||||
|
||||
private:
|
||||
std::string in_name() const;
|
||||
};
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -0,0 +1,109 @@
|
|||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "material.h"
|
||||
#include "node_parser.h"
|
||||
|
||||
#include <MaterialXFormat/XmlIo.h>
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "NOD_shader.h"
|
||||
|
||||
namespace blender::nodes::materialx {
|
||||
|
||||
class DefaultMaterialNodeParser : public NodeParser {
|
||||
public:
|
||||
using NodeParser::NodeParser;
|
||||
|
||||
NodeItem compute() override
|
||||
{
|
||||
NodeItem surface = create_node(
|
||||
"standard_surface",
|
||||
NodeItem::Type::SurfaceShader,
|
||||
BogdanNagirniak marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
This should create a temporary copy of the node tree with Node groups might ideally be preserved in export, but it would be easiest to start with exporting them expanded. For this it would be easiest to use the functions also called from
This should create a temporary copy of the node tree with `ntreeLocalize`, similar as is done for generating the GLSL shader. That will resolve any muting and reroute nodes, as handling them as part of the export process is not easy.
Node groups might ideally be preserved in export, but it would be easiest to start with exporting them expanded. For this it would be easiest to use the functions also called from `ntreeGPUMaterialNodes`:
```
ntree_shader_groups_remove_muted_links(localtree);
ntree_shader_groups_expand_inputs(localtree);
ntree_shader_groups_flatten(localtree);
```
Bogdan Nagirniak
commented
Exporting of group nodes is implemented in Exporting of group nodes is implemented in `materialx/group_nodes.cc/.h`
|
||||
{{"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));
|
||||
}
|
||||
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, {{"surfaceshader", surface}});
|
||||
res.node->setName("Material_Default");
|
||||
return res;
|
||||
}
|
||||
|
||||
NodeItem compute_error()
|
||||
{
|
||||
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");
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
||||
Material *material,
|
||||
ExportImageFunction export_image_fn)
|
||||
{
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name);
|
||||
|
||||
MaterialX::DocumentPtr doc = MaterialX::createDocument();
|
||||
if (material->use_nodes) {
|
||||
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()),
|
||||
export_image_fn};
|
||||
output_node->typeinfo->materialx_fn(&data, output_node, nullptr);
|
||||
}
|
||||
else {
|
||||
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,
|
||||
export_image_fn)
|
||||
.compute();
|
||||
}
|
||||
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER,
|
||||
1,
|
||||
"Material: %s\n%s",
|
||||
material->id.name,
|
||||
MaterialX::writeToXmlString(doc).c_str());
|
||||
return doc;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <MaterialXCore/Document.h>
|
||||
|
||||
struct Depsgraph;
|
||||
struct Material;
|
||||
|
||||
class ExportImageFunction;
|
||||
|
||||
namespace blender::nodes::materialx {
|
||||
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
||||
Material *material,
|
||||
ExportImageFunction export_image_fn);
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -0,0 +1,161 @@
|
|||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <MaterialXCore/Node.h>
|
||||
|
||||
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:
|
||||
using Inputs = std::vector<std::pair<std::string, NodeItem>>;
|
||||
|
||||
enum class Type {
|
||||
Any = 0,
|
||||
Empty,
|
||||
Multioutput,
|
||||
|
||||
/* Value types */
|
||||
String,
|
||||
Filename,
|
||||
Boolean,
|
||||
Integer,
|
||||
|
||||
/* Arithmetic types. NOTE: Ordered by type cast */
|
||||
Float,
|
||||
Vector2,
|
||||
Vector3,
|
||||
Color3,
|
||||
Vector4,
|
||||
Color4,
|
||||
|
||||
/* Shader types. NOTE: There are only supported types */
|
||||
BSDF,
|
||||
EDF,
|
||||
DisplacementShader,
|
||||
SurfaceShader,
|
||||
Material,
|
||||
|
||||
/* Special type to retrieve opacity for <surface> */
|
||||
SurfaceOpacity,
|
||||
};
|
||||
enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq };
|
||||
|
||||
public:
|
||||
MaterialX::ValuePtr value;
|
||||
MaterialX::NodePtr node;
|
||||
MaterialX::InputPtr input;
|
||||
MaterialX::OutputPtr output;
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
static Type type(const std::string &type_str);
|
||||
static std::string type(Type type);
|
||||
static bool is_arithmetic(Type type);
|
||||
|
||||
/* Operators */
|
||||
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;
|
||||
NodeItem operator[](int index) const;
|
||||
bool operator==(const NodeItem &other) const;
|
||||
bool operator!=(const NodeItem &other) const;
|
||||
|
||||
/* Math functions */
|
||||
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 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;
|
||||
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 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;
|
||||
|
||||
/* Useful functions */
|
||||
NodeItem empty() const;
|
||||
template<class T> NodeItem val(const T &data) const;
|
||||
Type type() const;
|
||||
|
||||
/* Node functions */
|
||||
NodeItem create_node(const std::string &category, Type type) const;
|
||||
NodeItem create_node(const std::string &category, Type type, const Inputs &inputs) const;
|
||||
template<class T> 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
bool is_arithmetic() const;
|
||||
NodeItem arithmetic(const std::string &category, std::function<float(float)> func) const;
|
||||
NodeItem arithmetic(const NodeItem &other,
|
||||
const std::string &category,
|
||||
std::function<float(float, float)> func,
|
||||
Type to_type = Type::Any) const;
|
||||
};
|
||||
|
||||
template<class T> NodeItem NodeItem::val(const T &data) const
|
||||
{
|
||||
NodeItem res(graph_);
|
||||
res.value = MaterialX::Value::createValue<T>(data);
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void NodeItem::set_input(const std::string &in_name, const T &value, Type in_type)
|
||||
{
|
||||
node->setInputValue(in_name, value, type(in_type));
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -0,0 +1,270 @@
|
|||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "node_parser.h"
|
||||
|
||||
#include "group_nodes.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,
|
||||
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),
|
||||
export_image_fn_(export_image_fn)
|
||||
{
|
||||
}
|
||||
|
||||
NodeItem NodeParser::compute_full()
|
||||
{
|
||||
NodeItem res = empty();
|
||||
|
||||
/* Checking if node was already computed */
|
||||
res.node = graph_->getNode(node_name());
|
||||
if (!res.node) {
|
||||
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() const
|
||||
{
|
||||
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, NodeItem::Type::SurfaceOpacity)) {
|
||||
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<const bNodeTree *>(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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type)
|
||||
{
|
||||
return get_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, false);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_link(int index, NodeItem::Type 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)
|
||||
{
|
||||
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::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_);
|
||||
}
|
||||
|
||||
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(name);
|
||||
if (!res.node) {
|
||||
res = create_node("texcoord", type);
|
||||
res.node->setName(name);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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 */
|
||||
break;
|
||||
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: {
|
||||
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,
|
||||
bool use_group_default)
|
||||
{
|
||||
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->is_reroute()) {
|
||||
link = from_node->input_socket(0).link;
|
||||
if (!(link && link->is_used())) {
|
||||
return empty();
|
||||
}
|
||||
from_node = link->fromnode;
|
||||
}
|
||||
|
||||
if (from_node->is_group()) {
|
||||
return GroupNodeParser(graph_,
|
||||
depsgraph_,
|
||||
material_,
|
||||
from_node,
|
||||
link->fromsock,
|
||||
to_type,
|
||||
group_parser_,
|
||||
export_image_fn_,
|
||||
use_group_default)
|
||||
.compute_full();
|
||||
}
|
||||
if (from_node->is_group_input()) {
|
||||
return GroupInputNodeParser(graph_,
|
||||
depsgraph_,
|
||||
material_,
|
||||
from_node,
|
||||
link->fromsock,
|
||||
to_type,
|
||||
group_parser_,
|
||||
export_image_fn_,
|
||||
use_group_default)
|
||||
.compute_full();
|
||||
}
|
||||
|
||||
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, group_parser_, empty(), export_image_fn_};
|
||||
from_node->typeinfo->materialx_fn(&data, const_cast<bNode *>(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, true);
|
||||
if (!res) {
|
||||
res = get_default(socket, to_type);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -0,0 +1,139 @@
|
|||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "node_item.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#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 GroupNodeParser;
|
||||
|
||||
using ExportImageFunction = std::function<std::string(Main *, Scene *, Image *, ImageUser *)>;
|
||||
|
||||
/**
|
||||
* 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_;
|
||||
const Depsgraph *depsgraph_;
|
||||
const Material *material_;
|
||||
const bNode *node_;
|
||||
const bNodeSocket *socket_out_;
|
||||
NodeItem::Type to_type_;
|
||||
GroupNodeParser *group_parser_;
|
||||
ExportImageFunction export_image_fn_;
|
||||
|
||||
public:
|
||||
NodeParser(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);
|
||||
virtual ~NodeParser() = default;
|
||||
|
||||
virtual NodeItem compute() = 0;
|
||||
virtual NodeItem compute_full();
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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 {
|
||||
MaterialX::GraphElement *graph;
|
||||
const Depsgraph *depsgraph;
|
||||
const Material *material;
|
||||
NodeItem::Type to_type;
|
||||
GroupNodeParser *group_parser;
|
||||
NodeItem result;
|
||||
ExportImageFunction export_image_fn;
|
||||
};
|
||||
|
||||
#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<materialx::NodeParserData *>(data); \
|
||||
d->result = MaterialXNodeParser(d->graph, \
|
||||
d->depsgraph, \
|
||||
d->material, \
|
||||
node, \
|
||||
out, \
|
||||
d->to_type, \
|
||||
d->group_parser, \
|
||||
d->export_image_fn) \
|
||||
.compute_full(); \
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
|
@ -22,6 +22,13 @@
|
|||
|
||||
#include "node_shader_register.hh"
|
||||
|
||||
#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;
|
||||
struct bNodeExecContext;
|
||||
|
|
|
@ -22,6 +22,33 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "node_add_shader", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF, NodeItem::Type::SurfaceOpacity)) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (to_type_ == NodeItem::Type::SurfaceOpacity) {
|
||||
return (shader1 + shader2) * val(0.5f);
|
||||
}
|
||||
return shader1 + shader2;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_add_shader_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -34,6 +61,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* <geompropvalue>) */
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 isn't supported by 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);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,23 @@ 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
|
||||
#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.
|
||||
*
|
||||
* NodeItem temperature = get_input_value("Temperature", NodeItem::Type::Float);
|
||||
|
||||
* NodeItem res = create_node("blackbody", NodeItem::Type::Color3);
|
||||
* res.set_input("temperature", temperature);
|
||||
* return res; */
|
||||
NodeItem res = empty();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_blackbody_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -44,6 +61,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);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,19 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "brightness_contrast", in, out);
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_brightness_cc
|
||||
|
||||
void register_node_type_sh_brightcontrast()
|
||||
|
@ -34,6 +47,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);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,24 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "node_bsdf_diffuse", 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);
|
||||
|
||||
return create_node("oren_nayar_diffuse_bsdf",
|
||||
NodeItem::Type::BSDF,
|
||||
{{"color", color}, {"roughness", roughness}, {"normal", normal}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_diffuse_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -48,6 +66,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);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,29 @@ 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);
|
||||
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_glass_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -57,6 +80,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);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,36 @@ 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,
|
||||
{{"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);
|
||||
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_glossy_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -72,6 +102,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);
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "node_shader_util.hh"
|
||||
|
@ -319,6 +321,272 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
|
|||
sss_method != SHD_SUBSURFACE_BURLEY);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
using InputsType = std::map<std::string, NodeItem>;
|
||||
|
||||
/* NOTE: commented inputs aren't used for node creation. */
|
||||
auto bsdf_inputs = [&]() -> InputsType {
|
||||
return {
|
||||
{"base_color", get_input_value("Base Color", NodeItem::Type::Color3)},
|
||||
{"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 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 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 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 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)},
|
||||
{"tangent", get_input_link("Tangent", NodeItem::Type::Vector3)},
|
||||
};
|
||||
};
|
||||
|
||||
auto edf_inputs = [&]() -> InputsType {
|
||||
return {
|
||||
{"emission", get_input_value("Emission Strength", NodeItem::Type::Float)},
|
||||
{"emission_color", get_input_value("Emission Color", NodeItem::Type::Color3)},
|
||||
};
|
||||
};
|
||||
|
||||
NodeItem res = empty();
|
||||
|
||||
switch (to_type_) {
|
||||
case NodeItem::Type::BSDF: {
|
||||
auto in = bsdf_inputs();
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
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 = n_coat_affect_roughness_multiply2.mix(roughness,
|
||||
val(1.0f));
|
||||
|
||||
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 = 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_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 = in["subsurface"].mix(n_diffuse_bsdf, n_subsurface_bsdf);
|
||||
|
||||
NodeItem n_sheen_layer = create_node(
|
||||
"layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}});
|
||||
|
||||
NodeItem n_transmission_mix = in["transmission"].mix(n_sheen_layer, n_transmission_bsdf);
|
||||
|
||||
NodeItem n_specular_layer = create_node(
|
||||
"layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}});
|
||||
|
||||
NodeItem n_metalness_mix = in["metallic"].mix(n_specular_layer, n_metal_bsdf);
|
||||
|
||||
NodeItem n_thin_film_layer = create_node(
|
||||
"layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}});
|
||||
|
||||
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"]).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"]},
|
||||
{"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();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_principled_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -335,6 +603,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);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,29 @@ 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);
|
||||
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_refraction_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -55,6 +78,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);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,24 @@ 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);
|
||||
|
||||
return create_node("sheen_bsdf",
|
||||
NodeItem::Type::BSDF,
|
||||
{{"color", color}, {"roughness", roughness}, {"normal", normal}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_sheen_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -62,6 +80,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);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,22 @@ 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);
|
||||
|
||||
return create_node(
|
||||
"translucent_bsdf", NodeItem::Type::BSDF, {{"color", color}, {"normal", normal}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_bsdf_translucent_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -42,6 +58,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);
|
||||
}
|
||||
|
|
|
@ -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 - <average of color components> */
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,27 @@ 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);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_clamp_cc
|
||||
|
||||
void register_node_type_sh_clamp()
|
||||
|
@ -84,6 +105,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);
|
||||
}
|
||||
|
|
|
@ -136,6 +136,16 @@ static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilde
|
|||
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* TODO: Implement */
|
||||
NodeItem res = empty();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_color_ramp_cc
|
||||
|
||||
void register_node_type_sh_valtorgb()
|
||||
|
@ -151,6 +161,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);
|
||||
}
|
||||
|
|
|
@ -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,20 @@ static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &bui
|
|||
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_curves_cc
|
||||
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
|
||||
|
||||
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 +133,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 +261,20 @@ static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &bui
|
|||
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_curves_cc
|
||||
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
|
||||
|
||||
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 +285,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 +389,20 @@ static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &b
|
|||
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_curves_cc
|
||||
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
|
||||
|
||||
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 +413,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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);
|
||||
|
||||
return create_node("uniform_edf", NodeItem::Type::EDF, {{"color", color * strength}});
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* <artistic_ior>) */
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@ 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
|
||||
|
||||
void register_node_type_sh_gamma()
|
||||
|
@ -34,6 +44,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);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,30 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
|
|||
return success;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* NOTE: Some outputs aren't supported by MaterialX.*/
|
||||
NodeItem res = empty();
|
||||
std::string name = socket_out_->name;
|
||||
|
||||
if (name == "Position") {
|
||||
res = create_node("position", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}});
|
||||
}
|
||||
else if (name == "Normal") {
|
||||
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, {{"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 +94,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,27 @@ static int gpu_shader_hue_sat(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "hue_sat", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* 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, {{"in1", hue}, {"in2", saturation}, {"in3", value}});
|
||||
|
||||
return create_node("hsvadjust", NodeItem::Type::Color3, {{"in", color}, {"amount", combine}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_hueSatVal_cc
|
||||
|
||||
void register_node_type_sh_hue_sat()
|
||||
|
@ -42,6 +63,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);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,16 @@ static int gpu_shader_invert(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "invert", in, out);
|
||||
}
|
||||
|
||||
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.mix(color, val(1.0f) - color);
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_invert_cc
|
||||
|
||||
void register_node_type_sh_invert()
|
||||
|
@ -37,6 +47,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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* <artistic_ior>) */
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,19 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "node_light_falloff", in, out);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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 / (smooth + val(1.0f));
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_light_falloff_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -37,6 +50,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);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,22 @@ static int node_shader_gpu_light_path(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "node_light_path", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* NOTE: 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);
|
||||
}
|
||||
NodeItem res = val(0.0f);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_light_path_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -44,6 +60,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);
|
||||
}
|
||||
|
|
|
@ -442,6 +442,51 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui
|
|||
}
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* TODO: Implement steps */
|
||||
|
||||
const NodeMapRange *map_range = static_cast<NodeMapRange *>(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();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_map_range_cc
|
||||
|
||||
void register_node_type_sh_map_range()
|
||||
|
@ -461,5 +506,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);
|
||||
}
|
||||
|
|
|
@ -74,6 +74,38 @@ 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 vector = get_input_value("Vector", NodeItem::Type::Vector3);
|
||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Vector3);
|
||||
NodeItem rotation = get_input_value("Rotation", NodeItem::Type::Vector3) *
|
||||
val(float(180.0f / M_PI));
|
||||
|
||||
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 empty();
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_mapping_cc
|
||||
|
||||
void register_node_type_sh_mapping()
|
||||
|
@ -87,6 +119,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);
|
||||
}
|
||||
|
|
|
@ -177,6 +177,172 @@ 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_math_cc
|
||||
|
||||
void register_node_type_sh_math()
|
||||
|
@ -192,6 +358,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,32 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "node_mix_shader", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
if (!ELEM(to_type_, NodeItem::Type::BSDF, NodeItem::Type::EDF, NodeItem::Type::SurfaceOpacity)) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_mix_shader_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -35,6 +61,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -122,6 +122,38 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
|
|||
return true;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeShaderNormalMap *normal_map_node = static_cast<NodeShaderNormalMap *>(node_->storage);
|
||||
NodeItem color = get_input_value("Color", NodeItem::Type::Vector3);
|
||||
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();
|
||||
}
|
||||
|
||||
return create_node("normalmap",
|
||||
NodeItem::Type::Vector3,
|
||||
{{"in", color}, {"scale", strength}, {"space", val(space)}});
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,33 @@ 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 isn't supported by MaterialX.*/
|
||||
NodeItem res = empty();
|
||||
std::string name = socket_out_->name;
|
||||
|
||||
if (name == "Location") {
|
||||
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.
|
||||
* 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 +68,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);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,25 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
|
|||
return true;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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) {
|
||||
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}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_output_material_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -56,6 +75,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;
|
||||
|
||||
|
|
|
@ -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 isn't supported by 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);
|
||||
}
|
||||
|
|
|
@ -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 isn't supported by 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);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,15 @@ 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);
|
||||
return create_node("constant", NodeItem::Type::Color4, {{"value", color}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_rgb_cc
|
||||
|
||||
void register_node_type_sh_rgb()
|
||||
|
@ -37,6 +46,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);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,15 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
|
|||
return GPU_stack_link(mat, node, "rgbtobw", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem color = get_input_value("Color", NodeItem::Type::Color4);
|
||||
return create_node("luminance", NodeItem::Type::Color4, {{"in", color}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_rgb_to_bw_cc
|
||||
|
||||
void register_node_type_sh_rgbtobw()
|
||||
|
@ -38,6 +47,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);
|
||||
}
|
||||
|
|
|
@ -68,6 +68,32 @@ static int gpu_shader_sepcolor(GPUMaterial *mat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
int mode = static_cast<NodeCombSepColor *>(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, {{"in", color}});
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2;
|
||||
return convert[index];
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_separate_color_cc
|
||||
|
||||
void register_node_type_sh_sepcolor()
|
||||
|
@ -83,6 +109,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 +163,38 @@ static int gpu_shader_combcolor(GPUMaterial *mat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
int mode = static_cast<NodeCombSepColor *>(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;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_combine_color_cc
|
||||
|
||||
void register_node_type_sh_combcolor()
|
||||
|
@ -151,6 +210,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);
|
||||
}
|
||||
|
|
|
@ -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,21 @@ 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
|
||||
#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[index];
|
||||
}
|
||||
#endif
|
||||
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 +112,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 +146,23 @@ 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
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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);
|
||||
|
||||
return create_node("combine3", NodeItem::Type::Vector3, {{"in1", x}, {"in2", y}, {"in3", z}});
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,31 @@ 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);
|
||||
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_subsurface_scattering_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -95,6 +120,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);
|
||||
}
|
||||
|
|
|
@ -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: implement other features */
|
||||
return create_node("tangent", NodeItem::Type::Vector3, {{"space", val(std::string("world"))}});
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -102,6 +102,28 @@ static void sh_node_tex_checker_build_multi_function(NodeMultiFunctionBuilder &b
|
|||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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[0].floor() + vector[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
|
||||
|
||||
void register_node_type_sh_tex_checker()
|
||||
|
@ -117,6 +139,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);
|
||||
}
|
||||
|
|
|
@ -71,6 +71,31 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
|
|||
return 1;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* NOTE: Some outputs aren't supported by 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, {{"space", val(std::string("world"))}});
|
||||
}
|
||||
else if (name == "Object") {
|
||||
res = create_node("position", NodeItem::Type::Vector3, {{"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 +109,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);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "IMB_colormanagement.h"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
namespace blender::nodes::node_shader_tex_environment_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
|
@ -127,6 +129,57 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
|
|||
return true;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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<NodeTexEnvironment *>(node_->storage);
|
||||
|
||||
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) {
|
||||
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
|
||||
|
||||
} // namespace blender::nodes::node_shader_tex_environment_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -144,6 +197,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);
|
||||
}
|
||||
|
|
|
@ -147,6 +147,50 @@ static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &
|
|||
builder.construct_and_set_matching_fn<GradientFunction>(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[0];
|
||||
break;
|
||||
case SHD_BLEND_QUADRATIC:
|
||||
res = vector[0];
|
||||
res = res * res;
|
||||
break;
|
||||
case SHD_BLEND_EASING:
|
||||
res = vector[0].clamp();
|
||||
res = res * res * (val(3.0f) - val(2.0f) * res);
|
||||
break;
|
||||
case SHD_BLEND_DIAGONAL:
|
||||
res = (vector[0] + vector[1]) * val(0.5f);
|
||||
break;
|
||||
case SHD_BLEND_RADIAL:
|
||||
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));
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "IMB_colormanagement.h"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
namespace blender::nodes::node_shader_tex_image_cc {
|
||||
|
||||
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
|
||||
|
@ -172,6 +174,87 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
|
|||
return true;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* Getting node name for Color output. This name will be used for <image> node. */
|
||||
std::string image_node_name = node_name();
|
||||
image_node_name = image_node_name.substr(0, image_node_name.rfind('_')) + "_Color";
|
||||
|
||||
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));
|
||||
|
||||
Image *image = (Image *)node_->id;
|
||||
if (image) {
|
||||
NodeTexImage *tex_image = static_cast<NodeTexImage *>(node_->storage);
|
||||
|
||||
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) {
|
||||
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,
|
||||
{{"texcoord", vector},
|
||||
{"filtertype", val(filtertype)},
|
||||
{"uaddressmode", val(addressmode)},
|
||||
{"vaddressmode", val(addressmode)}});
|
||||
res.set_input("file", image_path, NodeItem::Type::Filename);
|
||||
res.node->setName(image_node_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (STREQ(socket_out_->name, "Alpha")) {
|
||||
res = res[3];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_tex_image_cc
|
||||
|
||||
void register_node_type_sh_tex_image()
|
||||
|
@ -188,6 +271,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);
|
||||
}
|
||||
|
|
|
@ -257,6 +257,26 @@ static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder
|
|||
builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions, storage.normalize);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
NodeItem position = create_node("position", NodeItem::Type::Vector3);
|
||||
position = position * scale;
|
||||
|
||||
return create_node("fractal3d",
|
||||
NodeItem::Type::Color3,
|
||||
{{"position", position},
|
||||
{"octaves", val(int(detail.value->asA<float>()))},
|
||||
{"lacunarity", lacunarity}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_tex_noise_cc
|
||||
|
||||
void register_node_type_sh_tex_noise()
|
||||
|
@ -274,6 +294,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);
|
||||
}
|
||||
|
|
|
@ -219,6 +219,96 @@ 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;
|
||||
|
||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
||||
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(NodeItem::Type::Vector3);
|
||||
}
|
||||
|
||||
/* adjusment to get result as Cycles */
|
||||
distortion = distortion * val(10.0f);
|
||||
detail_scale = detail_scale * val(10.0f);
|
||||
|
||||
NodeItem pos = vector * scale;
|
||||
NodeItem fractal = create_node("fractal3d",
|
||||
NodeItem::Type::Float,
|
||||
{{"position", pos},
|
||||
{"octaves", val(int(detail.value->asA<float>()))},
|
||||
{"lacunarity", val(2.0f)}});
|
||||
NodeItem value = val(0.0f);
|
||||
switch (tex->wave_type) {
|
||||
case SHD_WAVE_BANDS:
|
||||
switch (tex->bands_direction) {
|
||||
case SHD_WAVE_BANDS_DIRECTION_X:
|
||||
value = pos[0] * val(20.0f);
|
||||
break;
|
||||
case SHD_WAVE_BANDS_DIRECTION_Y:
|
||||
value = pos[1] * val(20.0f);
|
||||
break;
|
||||
case SHD_WAVE_BANDS_DIRECTION_Z:
|
||||
value = pos[2] * val(20.0f);
|
||||
break;
|
||||
case SHD_WAVE_BANDS_DIRECTION_DIAGONAL:
|
||||
value = (pos[0] + pos[1] + pos[2]) * val(10.0f);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
break;
|
||||
case SHD_WAVE_RINGS:
|
||||
NodeItem rpos = pos;
|
||||
switch (tex->rings_direction) {
|
||||
case SHD_WAVE_RINGS_DIRECTION_X:
|
||||
rpos = pos * val(MaterialX::Vector3(0.0f, 1.0f, 1.0f));
|
||||
break;
|
||||
case SHD_WAVE_RINGS_DIRECTION_Y:
|
||||
rpos = pos * val(MaterialX::Vector3(1.0f, 0.0f, 1.0f));
|
||||
break;
|
||||
case SHD_WAVE_RINGS_DIRECTION_Z:
|
||||
rpos = pos * val(MaterialX::Vector3(1.0f, 1.0f, 0.0f));
|
||||
break;
|
||||
case SHD_WAVE_RINGS_DIRECTION_SPHERICAL:
|
||||
/* Ignore. */
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
value = rpos.length() * val(20.0f);
|
||||
break;
|
||||
}
|
||||
value = value + phase_offset + distortion * detail_scale * fractal;
|
||||
|
||||
NodeItem res = empty();
|
||||
switch (tex->wave_profile) {
|
||||
case SHD_WAVE_PROFILE_SIN:
|
||||
res = val(0.5f) + val(0.5f) * (value - val(float(M_PI_2))).sin();
|
||||
break;
|
||||
case SHD_WAVE_PROFILE_SAW:
|
||||
value = value / val(float(M_PI * 2.0f));
|
||||
res = value - value.floor();
|
||||
break;
|
||||
case SHD_WAVE_PROFILE_TRI:
|
||||
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 res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_tex_wave_cc
|
||||
|
||||
void register_node_type_sh_tex_wave()
|
||||
|
@ -235,6 +325,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);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,18 @@ 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
|
||||
*/
|
||||
NodeItem res = texcoord_node();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_uvmap_cc
|
||||
|
||||
/* node type definition */
|
||||
|
@ -84,6 +96,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);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,15 @@ static void sh_node_value_build_multi_function(NodeMultiFunctionBuilder &builder
|
|||
builder.construct_and_set_matching_fn<mf::CustomMF_Constant<float>>(value->value);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
NodeItem value = get_output_default("Value", NodeItem::Type::Float);
|
||||
return create_node("constant", NodeItem::Type::Float, {{"value", value}});
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_value_cc
|
||||
|
||||
void register_node_type_sh_value()
|
||||
|
@ -50,6 +59,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -316,6 +316,123 @@ static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &b
|
|||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_vector_math_cc
|
||||
|
||||
void register_node_type_sh_vect_math()
|
||||
|
@ -332,6 +449,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);
|
||||
}
|
||||
|
|
|
@ -212,6 +212,49 @@ 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
|
||||
{
|
||||
int mode = node_->custom1;
|
||||
bool invert = node_->custom2;
|
||||
|
||||
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));
|
||||
vector = vector - center;
|
||||
|
||||
if (mode == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
|
||||
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;
|
||||
}
|
||||
|
||||
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_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.rotate(invert ? -angle : angle, axis) + center;
|
||||
}
|
||||
#endif
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_vector_rotate_cc
|
||||
|
||||
void register_node_type_sh_vector_rotate()
|
||||
|
@ -226,6 +269,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* <geomcolor>)*/
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,15 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
|
|||
}
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
#ifdef WITH_MATERIALX
|
||||
{
|
||||
/* NOTE: This node isn't supported by 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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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<io::hydra::HydraSceneDelegate>(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);
|
||||
}
|
||||
|
|
I would name this just
NodeMaterialXFunction
, theExec
is from a time when these functions actually executed the nodes.