MaterialX: fix review comments #19

Merged
Bogdan Nagirniak merged 10 commits from matx-fix-review-comments into matx-export-material 2023-09-14 02:01:04 +02:00
71 changed files with 1321 additions and 1789 deletions
Showing only changes of commit 86f366f002 - Show all commits

View File

@ -225,6 +225,9 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
struct bNodeExecData *execdata, struct bNodeExecData *execdata,
struct GPUNodeStack *in, struct GPUNodeStack *in,
struct GPUNodeStack *out); struct GPUNodeStack *out);
typedef void (*NodeMaterialXExecFunction)(void *data,
struct bNode *node,
struct bNodeSocket *out);
/** /**
* \brief Defines a node type. * \brief Defines a node type.
@ -339,6 +342,8 @@ typedef struct bNodeType {
NodeExecFunction exec_fn; NodeExecFunction exec_fn;
/* gpu */ /* gpu */
NodeGPUExecFunction gpu_fn; NodeGPUExecFunction gpu_fn;
/* MaterialX */
NodeMaterialXExecFunction materialx_fn;
/* Get an instance of this node's compositor operation. Freeing the instance is the /* Get an instance of this node's compositor operation. Freeing the instance is the
* responsibility of the caller. */ * responsibility of the caller. */

View File

@ -147,44 +147,12 @@ set(LIB
if(WITH_MATERIALX) if(WITH_MATERIALX)
list(APPEND SRC list(APPEND SRC
materialx/material.cc materialx/material.cc
materialx/nodes/add_shader.cc materialx/node_item.cc
materialx/nodes/blackbody.cc materialx/node_parser.cc
materialx/nodes/brightness.cc
materialx/nodes/bsdf_diffuse.cc
materialx/nodes/bsdf_glass.cc
materialx/nodes/bsdf_glossy.cc
materialx/nodes/bsdf_principled.cc
materialx/nodes/bsdf_refraction.cc
materialx/nodes/bsdf_sheen.cc
materialx/nodes/bsdf_toon.cc
materialx/nodes/bsdf_translucent.cc
materialx/nodes/bsdf_transparent.cc
materialx/nodes/clamp.cc
materialx/nodes/emission.cc
materialx/nodes/huesatval.cc
materialx/nodes/invert.cc
materialx/nodes/map_range.cc
materialx/nodes/math.cc
materialx/nodes/mix_rgb.cc
materialx/nodes/mix_shader.cc
materialx/nodes/node_item.cc
materialx/nodes/node_parser.cc
materialx/nodes/normal_map.cc
materialx/nodes/output_material.cc
materialx/nodes/rgb_to_bw.cc
materialx/nodes/sepcomb_color.cc
materialx/nodes/sepcomb_xyz.cc
materialx/nodes/subsurface_scattering.cc
materialx/nodes/tex_checker.cc
materialx/nodes/tex_environment.cc
materialx/nodes/tex_image.cc
materialx/nodes/tex_noise.cc
materialx/nodes/vector_math.cc
materialx/material.h materialx/material.h
materialx/nodes/node_item.h materialx/node_item.h
materialx/nodes/node_parser.h materialx/node_parser.h
materialx/nodes/output_material.h
) )
list(APPEND LIB list(APPEND LIB
MaterialXCore MaterialXCore

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */ * SPDX-License-Identifier: GPL-2.0-or-later */
#include "material.h" #include "material.h"
#include "nodes/output_material.h" #include "node_parser.h"
#include <MaterialXFormat/XmlIo.h> #include <MaterialXFormat/XmlIo.h>
@ -15,7 +15,42 @@
namespace blender::nodes::materialx { namespace blender::nodes::materialx {
CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader"); class DefaultMaterialNodeParser : public NodeParser {
public:
using NodeParser::NodeParser;
NodeItem compute() override
{
NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader);
surface.set_input("base_color",
val(MaterialX::Color3(material_->r, material_->g, material_->b)));
surface.set_input("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);
res.node->setName("Material_Default");
res.set_input("surfaceshader", surface);
return res;
}
NodeItem compute_error()
{
NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader);
surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
NodeItem res = create_node("surfacematerial", NodeItem::Type::Material);
res.node->setName("Material_Error");
res.set_input("surfaceshader", surface);
return res;
}
};
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material) MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material)
{ {
@ -25,10 +60,21 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater
if (material->use_nodes) { if (material->use_nodes) {
material->nodetree->ensure_topology_cache(); material->nodetree->ensure_topology_cache();
bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL); bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL);
OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute_full(); if (output_node) {
NodeParserData data = {
doc.get(), depsgraph, material, NodeItem::Type::Material, NodeItem(doc.get())};
output_node->typeinfo->materialx_fn(&data, output_node, nullptr);
} }
else { else {
OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default(); DefaultMaterialNodeParser(
doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material)
.compute_error();
}
}
else {
DefaultMaterialNodeParser(
doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material)
.compute();
} }
CLOG_INFO(LOG_MATERIALX_SHADER, CLOG_INFO(LOG_MATERIALX_SHADER,

View File

@ -6,15 +6,11 @@
#include <MaterialXCore/Document.h> #include <MaterialXCore/Document.h>
#include "CLG_log.h"
struct Depsgraph; struct Depsgraph;
struct Material; struct Material;
namespace blender::nodes::materialx { namespace blender::nodes::materialx {
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material); MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material);
} // namespace blender::nodes::materialx } // namespace blender::nodes::materialx

View File

@ -3,7 +3,6 @@
* SPDX-License-Identifier: GPL-2.0-or-later */ * SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_item.h" #include "node_item.h"
#include "../material.h"
#include "BLI_assert.h" #include "BLI_assert.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
@ -63,6 +62,8 @@ NodeItem::Type NodeItem::type(const std::string &type_str)
std::string NodeItem::type(Type type) std::string NodeItem::type(Type type)
{ {
switch (type) { switch (type) {
case Type::Any:
return "";
case Type::String: case Type::String:
return "string"; return "string";
case Type::Filename: case Type::Filename:

View File

@ -53,6 +53,7 @@ class NodeItem {
static Type type(const std::string &type_str); static Type type(const std::string &type_str);
static std::string type(Type type); static std::string type(Type type);
static bool is_arithmetic(Type type);
/* Operators */ /* Operators */
operator bool() const; operator bool() const;
@ -112,7 +113,6 @@ class NodeItem {
void add_output(const std::string &in_name, Type out_type); void add_output(const std::string &in_name, Type out_type);
private: private:
static bool is_arithmetic(Type type);
static Type cast_types(NodeItem &item1, NodeItem &item2); static Type cast_types(NodeItem &item1, NodeItem &item2);
bool is_arithmetic() const; bool is_arithmetic() const;

View File

@ -0,0 +1,188 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.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)
: graph_(graph),
depsgraph_(depsgraph),
material_(material),
node_(node),
socket_out_(socket_out),
to_type_(to_type)
{
}
NodeItem NodeParser::compute_full()
{
NodeItem res = empty();
/* Checking if node was already computed */
res.node = graph_->getNode(node_name());
if (res.node) {
return res;
}
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()
{
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)) {
name += "_" + NodeItem::type(to_type_);
}
return MaterialX::createValidName(name);
}
NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type)
{
return empty().create_node(category, type);
}
NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type)
{
return get_input_default(node_->input_by_identifier(name), to_type);
}
NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type)
{
return get_input_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);
}
NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type)
{
return get_input_link(node_->input_socket(index), to_type);
}
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::empty() const
{
return NodeItem(graph_);
}
NodeItem NodeParser::texcoord_node()
{
NodeItem res = empty();
res.node = graph_->getNode(TEXCOORD_NODE_NAME);
if (!res.node) {
res = create_node("texcoord", NodeItem::Type::Vector2);
res.node->setName(TEXCOORD_NODE_NAME);
}
return res;
}
NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = empty();
switch (socket.type) {
case SOCK_FLOAT: {
float v = socket.default_value_typed<bNodeSocketValueFloat>()->value;
res.value = MaterialX::Value::createValue<float>(v);
break;
}
case SOCK_VECTOR: {
const float *v = socket.default_value_typed<bNodeSocketValueVector>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
MaterialX::Vector3(v[0], v[1], v[2]));
break;
}
case SOCK_RGBA: {
const float *v = socket.default_value_typed<bNodeSocketValueRGBA>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
MaterialX::Color4(v[0], v[1], v[2], v[3]));
break;
}
default: {
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)
{
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->type == NODE_REROUTE) {
link = from_node->input_socket(0).link;
if (!(link && link->is_used())) {
return empty();
}
from_node = link->fromnode;
}
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, empty()};
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);
if (!res) {
res = get_input_default(socket, to_type);
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -0,0 +1,96 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "node_item.h"
#include "DEG_depsgraph.h"
#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 NodeParser {
protected:
MaterialX::GraphElement *graph_;
const Depsgraph *depsgraph_;
const Material *material_;
const bNode *node_;
const bNodeSocket *socket_out_;
NodeItem::Type to_type_;
public:
NodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out,
NodeItem::Type to_type);
virtual ~NodeParser() = default;
virtual NodeItem compute() = 0;
virtual NodeItem compute_full();
protected:
std::string node_name();
NodeItem create_node(const std::string &category, NodeItem::Type type);
NodeItem get_input_default(const std::string &name, NodeItem::Type to_type);
NodeItem get_input_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();
private:
NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type);
NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type);
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
*/
struct NodeParserData {
MaterialX::GraphElement *graph;
const Depsgraph *depsgraph;
const Material *material;
NodeItem::Type to_type;
NodeItem result;
};
#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) \
.compute_full(); \
}
} // namespace blender::nodes::materialx

View File

@ -1,42 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem AddShaderNodeParser::compute()
{
NodeItem res = empty();
switch (shader_type_) {
case NodeItem::Type::BSDF:
case NodeItem::Type::EDF: {
NodeItem shader1 = get_input_shader(0, shader_type_);
NodeItem shader2 = get_input_shader(1, shader_type_);
if (shader1 && !shader2) {
res = shader1;
}
else if (!shader1 && shader2) {
res = shader2;
}
else if (shader1 && shader2) {
res = shader1 + shader2;
}
break;
}
case NodeItem::Type::SurfaceShader: {
res = get_input_shader(0, shader_type_);
if (!res) {
res = get_input_shader(1, shader_type_);
}
break;
}
default:
BLI_assert_unreachable();
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,22 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BlackbodyNodeParser::compute()
{
/* 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; */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,19 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BrightContrastNodeParser::compute()
{
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));
}
} // namespace blender::nodes::materialx

View File

@ -1,28 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFDiffuseNodeParser::compute()
{
if (shader_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);
NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF);
res.set_input("color", color);
res.set_input("roughness", roughness);
if (normal) {
res.set_input("normal", normal);
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFGlassNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFGlossyNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,101 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFPrincipledNodeParser::compute()
{
if (shader_type_ != NodeItem::Type::SurfaceShader) {
/* TODO: implement for BSDF and EDF */
return empty();
}
NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3);
NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float);
NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3);
NodeItem subsurface_color = get_input_value("Subsurface Color", NodeItem::Type::Color3);
NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float);
NodeItem specular = get_input_value("Specular", NodeItem::Type::Float);
// NodeItem specular_tint = get_input_value("Specular Tint");
NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float);
/* TODO: use Specular Tint input */
NodeItem anisotropic = get_input_value("Anisotropic", NodeItem::Type::Float);
NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation", NodeItem::Type::Float);
// anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0)
NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float);
// sheen_tint = get_input_value("Sheen Tint");
NodeItem clearcoat = get_input_value("Clearcoat", NodeItem::Type::Float);
NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness", NodeItem::Type::Float);
NodeItem ior = get_input_value("IOR", NodeItem::Type::Float);
NodeItem transmission = get_input_value("Transmission", NodeItem::Type::Float);
NodeItem emission = get_input_value("Emission", NodeItem::Type::Color3);
NodeItem emission_strength = get_input_value("Emission Strength", NodeItem::Type::Float);
NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float);
// transparency = 1.0 - alpha
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3);
NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3);
/* Creating standard_surface */
NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader);
res.set_input("base", val(1.0f));
res.set_input("base_color", base_color);
res.set_input("diffuse_roughness", roughness);
if (normal) {
res.set_input("normal", normal);
}
if (tangent) {
res.set_input("tangent", tangent);
}
res.set_input("metalness", metallic);
res.set_input("specular", specular);
res.set_input("specular_color", base_color);
res.set_input("specular_roughness", roughness);
res.set_input("specular_IOR", ior);
res.set_input("specular_anisotropy", anisotropic);
res.set_input("specular_rotation", anisotropic_rotation);
res.set_input("transmission", transmission);
res.set_input("transmission_color", base_color);
res.set_input("transmission_extra_roughness", roughness);
res.set_input("subsurface", subsurface);
res.set_input("subsurface_color", subsurface_color);
res.set_input("subsurface_radius", subsurface_radius);
res.set_input("subsurface_anisotropy", anisotropic);
res.set_input("sheen", sheen);
res.set_input("sheen_color", base_color);
res.set_input("sheen_roughness", roughness);
res.set_input("coat", clearcoat);
res.set_input("coat_color", base_color);
res.set_input("coat_roughness", clearcoat_roughness);
res.set_input("coat_IOR", ior);
res.set_input("coat_anisotropy", anisotropic);
res.set_input("coat_rotation", anisotropic_rotation);
if (clearcoat_normal) {
res.set_input("coat_normal", clearcoat_normal);
}
res.set_input("emission", emission_strength);
res.set_input("emission_color", emission);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFRefractionNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFSheenNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFToonNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFTranslucentNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem BSDFTransparentNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,27 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem ClampNodeParser::compute()
{
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;
}
} // namespace blender::nodes::materialx

View File

@ -1,23 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem EmissionNodeParser::compute()
{
if (shader_type_ != NodeItem::Type::EDF) {
return empty();
}
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
NodeItem strength = get_input_value("Strength", NodeItem::Type::Float);
NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF);
res.set_input("color", color * strength);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,33 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem HueSatValNodeParser::compute()
{
/* TODO: implement fac, see do_hue_sat_fac in
* source\blender\nodes\texture\nodes\node_texture_hueSatVal.cc */
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);
combine.set_input("in1", hue);
combine.set_input("in2", saturation);
combine.set_input("in3", value);
NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3);
res.set_input("in", color);
res.set_input("amount", combine);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,16 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem InvertNodeParser::compute()
{
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
return fac.blend(color, fac.val(1.0f) - color);
}
} // namespace blender::nodes::materialx

View File

@ -1,51 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem MapRangeNodeParser::compute()
{
/* Interpolation isn't supported by MaterialX. */
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();
}
NodeItem res = create_node("range", type);
res.set_input("in", value);
res.set_input("inlow", from_min);
res.set_input("inhigh", from_max);
res.set_input("outlow", to_min);
res.set_input("outhigh", to_max);
res.set_input("doclamp", val(bool(map_range->clamp)));
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,171 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../material.h"
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem MathNodeParser::compute()
{
/* 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;
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem MixRGBNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,46 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem MixShaderNodeParser::compute()
{
NodeItem res = empty();
switch (shader_type_) {
case NodeItem::Type::BSDF:
case NodeItem::Type::EDF: {
NodeItem fac = get_input_value(0, NodeItem::Type::Float);
NodeItem shader1 = get_input_shader(1, shader_type_);
NodeItem shader2 = get_input_shader(2, shader_type_);
if (shader1 && !shader2) {
res = shader1 * (val(1.0f) - fac);
}
else if (!shader1 && shader2) {
res = shader2 * fac;
}
else if (shader1 && shader2) {
res = create_node("mix", shader_type_);
res.set_input("fg", shader1);
res.set_input("bg", shader2);
res.set_input("mix", fac);
}
break;
}
case NodeItem::Type::SurfaceShader: {
res = get_input_shader(1, NodeItem::Type::SurfaceShader);
if (!res) {
res = get_input_shader(2, NodeItem::Type::SurfaceShader);
}
break;
}
default:
BLI_assert_unreachable();
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,311 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
#include "../material.h"
#include "BKE_node_runtime.hh"
namespace blender::nodes::materialx {
static const std::string TEXCOORD_NODE_NAME = "node_texcoord";
NodeParser::NodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out)
: graph_(graph),
depsgraph_(depsgraph),
material_(material),
node_(node),
socket_out_(socket_out)
{
}
NodeItem NodeParser::compute_full()
{
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type);
NodeItem res = compute();
if (res.node) {
res.node->setName(node_name());
}
return res;
}
std::string NodeParser::node_name()
{
return MaterialX::createValidName(node_->output_sockets().size() <= 1 ?
std::string(node_->name) :
std::string(node_->name) + "_" + socket_out_->name);
}
NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type type)
{
return empty().create_node(category, type);
}
NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type)
{
return get_input_default(node_->input_by_identifier(name), to_type);
}
NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type)
{
return get_input_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);
}
NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type)
{
return get_input_link(node_->input_socket(index), to_type);
}
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::empty() const
{
return NodeItem(graph_);
}
NodeItem NodeParser::texcoord_node()
{
NodeItem res = empty();
res.node = graph_->getNode(TEXCOORD_NODE_NAME);
if (!res.node) {
res = create_node("texcoord", NodeItem::Type::Vector2);
res.node->setName(TEXCOORD_NODE_NAME);
}
return res;
}
NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = empty();
switch (socket.type) {
case SOCK_FLOAT: {
float v = socket.default_value_typed<bNodeSocketValueFloat>()->value;
res.value = MaterialX::Value::createValue<float>(v);
break;
}
case SOCK_VECTOR: {
const float *v = socket.default_value_typed<bNodeSocketValueVector>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
MaterialX::Vector3(v[0], v[1], v[2]));
break;
}
case SOCK_RGBA: {
const float *v = socket.default_value_typed<bNodeSocketValueRGBA>()->value;
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
MaterialX::Color4(v[0], v[1], v[2], v[3]));
break;
}
default: {
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)
{
NodeItem res = empty();
const bNodeLink *link = socket.link;
if (!(link && link->is_used())) {
return res;
}
const bNode *from_node = link->fromnode;
/* Passing NODE_REROUTE nodes */
while (from_node->type == NODE_REROUTE) {
link = from_node->input_socket(0).link;
if (!(link && link->is_used())) {
return res;
}
from_node = link->fromnode;
}
/* Creating required NodeParser object */
std::unique_ptr<NodeParser> parser;
#define CASE_NODE_TYPE(type, T) \
case type: \
parser = std::make_unique<T>(graph_, depsgraph_, material_, from_node, link->fromsock); \
break;
switch (from_node->typeinfo->type) {
CASE_NODE_TYPE(SH_NODE_BLACKBODY, BlackbodyNodeParser)
CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser)
CASE_NODE_TYPE(SH_NODE_CLAMP, ClampNodeParser)
CASE_NODE_TYPE(SH_NODE_COMBINE_COLOR, CombineColorNodeParser)
CASE_NODE_TYPE(SH_NODE_COMBXYZ, CombineXYZNodeParser)
CASE_NODE_TYPE(SH_NODE_HUE_SAT, HueSatValNodeParser)
CASE_NODE_TYPE(SH_NODE_INVERT, InvertNodeParser)
CASE_NODE_TYPE(SH_NODE_MAP_RANGE, MapRangeNodeParser)
CASE_NODE_TYPE(SH_NODE_MATH, MathNodeParser)
CASE_NODE_TYPE(SH_NODE_MIX_RGB_LEGACY, MixRGBNodeParser)
CASE_NODE_TYPE(SH_NODE_NORMAL_MAP, NormalMapNodeParser)
CASE_NODE_TYPE(SH_NODE_RGBTOBW, RGBToBWNodeParser)
CASE_NODE_TYPE(SH_NODE_SEPARATE_COLOR, SeparateColorNodeParser)
CASE_NODE_TYPE(SH_NODE_SEPXYZ, SeparateXYZNodeParser)
CASE_NODE_TYPE(SH_NODE_TEX_CHECKER, TexCheckerNodeParser)
CASE_NODE_TYPE(SH_NODE_TEX_ENVIRONMENT, TexEnvironmentNodeParser)
CASE_NODE_TYPE(SH_NODE_TEX_IMAGE, TexImageNodeParser)
CASE_NODE_TYPE(SH_NODE_TEX_NOISE, TexNoiseNodeParser)
CASE_NODE_TYPE(SH_NODE_VECTOR_MATH, VectorMathNodeParser)
default:
CLOG_WARN(LOG_MATERIALX_SHADER,
"Unsupported node: %s [%d]",
from_node->name,
from_node->typeinfo->type);
}
if (!parser) {
return res;
}
/* Checking if node was already computed */
res.node = graph_->getNode(parser->node_name());
if (res.node) {
return res;
}
/* Computing */
res = parser->compute_full();
return res.convert(to_type);
}
NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = get_input_link(socket, to_type);
if (!res) {
res = get_input_default(socket, to_type);
}
return res;
}
ShaderNodeParser::ShaderNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out,
NodeItem::Type shader_type)
: NodeParser(graph, depsgraph, material, node, socket_out), shader_type_(shader_type)
{
}
NodeItem ShaderNodeParser::compute_full()
{
CLOG_INFO(LOG_MATERIALX_SHADER,
1,
"%s [%d] - %s",
node_->name,
node_->typeinfo->type,
NodeItem::type(shader_type_).c_str());
NodeItem res = compute();
if (res.node) {
res.node->setName(node_name());
}
return res;
}
std::string ShaderNodeParser::node_name()
{
std::string name = NodeParser::node_name();
if (shader_type_ != NodeItem::Type::SurfaceShader) {
name += "_" + NodeItem::type(shader_type_);
}
return name;
}
NodeItem ShaderNodeParser::get_input_shader(const std::string &name, NodeItem::Type shader_type)
{
return get_input_shader(node_->input_by_identifier(name), shader_type);
}
NodeItem ShaderNodeParser::get_input_shader(int index, NodeItem::Type shader_type)
{
return get_input_shader(node_->input_socket(index), shader_type);
}
NodeItem ShaderNodeParser::get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type)
{
NodeItem res = empty();
const bNodeLink *link = socket.link;
if (!(link && link->is_used())) {
return res;
}
const bNode *from_node = link->fromnode;
/* Passing NODE_REROUTE nodes */
while (from_node->type == NODE_REROUTE) {
link = from_node->input_socket(0).link;
if (!(link && link->is_used())) {
return res;
}
from_node = link->fromnode;
}
/* Creating required ShaderNodeParser object */
std::unique_ptr<ShaderNodeParser> parser;
#define CASE_SHADER_NODE_TYPE(type, T) \
case type: \
parser = std::make_unique<T>( \
graph_, depsgraph_, material_, from_node, link->fromsock, shader_type); \
break;
switch (from_node->typeinfo->type) {
CASE_SHADER_NODE_TYPE(SH_NODE_ADD_SHADER, AddShaderNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_DIFFUSE, BSDFDiffuseNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLASS, BSDFGlassNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_GLOSSY, BSDFGlossyNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_REFRACTION, BSDFRefractionNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_SHEEN, BSDFSheenNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TOON, BSDFToonNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSLUCENT, BSDFTranslucentNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_BSDF_TRANSPARENT, BSDFTransparentNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_EMISSION, EmissionNodeParser)
CASE_SHADER_NODE_TYPE(SH_NODE_MIX_SHADER, MixShaderNodeParser)
// CASE_SHADER_NODE_TYPE(SH_NODE_SUBSURFACE_SCATTERING, SubsurfaceScatteringNodeParser)
default:
CLOG_WARN(LOG_MATERIALX_SHADER,
"Unsupported node: %s [%d]",
from_node->name,
from_node->typeinfo->type);
}
if (!parser) {
return res;
}
/* Checking if node was already computed */
res.node = graph_->getNode(parser->node_name());
if (res.node) {
return res;
}
/* Computing */
res = parser->compute_full();
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,128 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "node_item.h"
#include "DEG_depsgraph.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
namespace blender::nodes::materialx {
class NodeParser {
protected:
MaterialX::GraphElement *graph_;
const Depsgraph *depsgraph_;
const Material *material_;
const bNode *node_;
const bNodeSocket *socket_out_;
public:
NodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out);
virtual ~NodeParser() = default;
virtual NodeItem compute() = 0;
protected:
virtual NodeItem compute_full();
virtual std::string node_name();
NodeItem create_node(const std::string &category, NodeItem::Type type);
NodeItem get_input_default(const std::string &name, NodeItem::Type to_type);
NodeItem get_input_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();
private:
NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type);
NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type);
NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type);
};
class ShaderNodeParser : public NodeParser {
protected:
NodeItem::Type shader_type_;
public:
ShaderNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node,
const bNodeSocket *socket_out,
NodeItem::Type shader_type);
protected:
NodeItem compute_full() override;
std::string node_name() override;
NodeItem get_input_shader(const std::string &name, NodeItem::Type shader_type);
NodeItem get_input_shader(int index, NodeItem::Type shader_type);
private:
NodeItem get_input_shader(const bNodeSocket &socket, NodeItem::Type shader_type);
};
template<class T> NodeItem NodeParser::val(const T &data) const
{
return empty().val(data);
}
#define DECLARE_NODE_PARSER(T) \
class T : public NodeParser { \
public: \
using NodeParser::NodeParser; \
NodeItem compute() override; \
};
#define DECLARE_SHADER_NODE_PARSER(T) \
class T : public ShaderNodeParser { \
public: \
using ShaderNodeParser::ShaderNodeParser; \
NodeItem compute() override; \
};
DECLARE_NODE_PARSER(BlackbodyNodeParser)
DECLARE_NODE_PARSER(BrightContrastNodeParser)
DECLARE_NODE_PARSER(ClampNodeParser)
DECLARE_NODE_PARSER(CombineColorNodeParser)
DECLARE_NODE_PARSER(CombineXYZNodeParser)
DECLARE_NODE_PARSER(HueSatValNodeParser)
DECLARE_NODE_PARSER(InvertNodeParser)
DECLARE_NODE_PARSER(MapRangeNodeParser)
DECLARE_NODE_PARSER(MathNodeParser)
DECLARE_NODE_PARSER(MixRGBNodeParser)
DECLARE_NODE_PARSER(NormalMapNodeParser)
DECLARE_NODE_PARSER(RGBToBWNodeParser)
DECLARE_NODE_PARSER(SeparateColorNodeParser)
DECLARE_NODE_PARSER(SeparateXYZNodeParser)
DECLARE_NODE_PARSER(TexCheckerNodeParser)
DECLARE_NODE_PARSER(TexEnvironmentNodeParser)
DECLARE_NODE_PARSER(TexImageNodeParser)
DECLARE_NODE_PARSER(TexNoiseNodeParser)
DECLARE_NODE_PARSER(VectorMathNodeParser)
DECLARE_SHADER_NODE_PARSER(AddShaderNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFDiffuseNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFGlassNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFGlossyNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFPrincipledNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFRefractionNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFSheenNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFToonNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFTranslucentNodeParser)
DECLARE_SHADER_NODE_PARSER(BSDFTransparentNodeParser)
DECLARE_SHADER_NODE_PARSER(EmissionNodeParser)
DECLARE_SHADER_NODE_PARSER(MixShaderNodeParser)
DECLARE_SHADER_NODE_PARSER(SubsurfaceScatteringNodeParser)
} // namespace blender::nodes::materialx

View File

@ -1,40 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../material.h"
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem NormalMapNodeParser::compute()
{
std::string default_space = "object";
NodeShaderNormalMap *normal_map_node = static_cast<NodeShaderNormalMap *>(node_->storage);
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
NodeItem strength = get_input_value("Strength", NodeItem::Type::Float);
NodeItem res = create_node("normalmap", NodeItem::Type::Vector3);
res.set_input("in", color);
res.set_input("scale", strength);
switch (normal_map_node->space) {
case SHD_SPACE_TANGENT:
res.set_input("space", val(std::string("tangent")));
break;
case SHD_SPACE_OBJECT:
res.set_input("space", val(std::string("tangent")));
break;
default:
res.set_input("space", val(default_space));
CLOG_WARN(LOG_MATERIALX_SHADER,
"Ignoring unsupported Space: %d %s (%d), %s will be used",
normal_map_node->space,
node_->name,
node_->type,
default_space);
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,70 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "output_material.h"
namespace blender::nodes::materialx {
OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node)
: ShaderNodeParser(graph, depsgraph, material, node, nullptr, NodeItem::Type::Material)
{
}
NodeItem OutputMaterialNodeParser::compute()
{
NodeItem surface = empty();
if (node_) {
NodeItem bsdf = get_input_shader("Surface", NodeItem::Type::BSDF);
NodeItem edf = get_input_shader("Surface", NodeItem::Type::EDF);
if (bsdf || edf) {
surface = create_node("surface", NodeItem::Type::SurfaceShader);
if (bsdf) {
surface.set_input("bsdf", bsdf);
}
if (edf) {
surface.set_input("edf", edf);
}
}
else {
surface = get_input_shader("Surface", NodeItem::Type::SurfaceShader);
}
}
else {
surface = create_node("standard_surface", NodeItem::Type::SurfaceShader);
surface.set_input("base_color", val(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
}
NodeItem res = create_node("surfacematerial", NodeItem::Type::Material);
res.set_input("surfaceshader", surface);
return res;
}
NodeItem OutputMaterialNodeParser::compute_default()
{
NodeItem surface = create_node("standard_surface", NodeItem::Type::SurfaceShader);
surface.set_input("base_color",
val(MaterialX::Color3(material_->r, material_->g, material_->b)));
surface.set_input("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);
res.node->setName("Material_Default");
res.set_input("surfaceshader", surface);
return res;
}
std::string OutputMaterialNodeParser::node_name()
{
return NodeParser::node_name();
}
} // namespace blender::nodes::materialx

View File

@ -1,26 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "node_parser.h"
namespace blender::nodes::materialx {
class OutputMaterialNodeParser : public ShaderNodeParser {
public:
OutputMaterialNodeParser(MaterialX::GraphElement *graph,
const Depsgraph *depsgraph,
const Material *material,
const bNode *node);
NodeItem compute() override;
using ShaderNodeParser::compute_full;
NodeItem compute_default();
protected:
std::string node_name() override;
};
} // namespace blender::nodes::materialx

View File

@ -1,18 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem RGBToBWNodeParser::compute()
{
NodeItem color = get_input_value("Color", NodeItem::Type::Color4);
NodeItem res = create_node("luminance", NodeItem::Type::Color4);
res.set_input("in", color);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,72 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../material.h"
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem SeparateColorNodeParser::compute()
{
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:
break;
case NODE_COMBSEP_COLOR_HSV:
convert = create_node("rgbtohsv", NodeItem::Type::Color3);
convert.set_input("in", color);
break;
case NODE_COMBSEP_COLOR_HSL:
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported color model, using HSV instead: %d", mode);
convert = create_node("rgbtohsv", NodeItem::Type::Color3);
convert.set_input("in", color);
break;
default:
BLI_assert_unreachable();
}
int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2;
NodeItem res = convert ? convert : color;
return res.extract(index);
}
NodeItem CombineColorNodeParser::compute()
{
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 convert = empty();
NodeItem combine = create_node("combine3", NodeItem::Type::Color3);
combine.set_input("in1", red);
combine.set_input("in2", green);
combine.set_input("in3", blue);
switch (mode) {
case NODE_COMBSEP_COLOR_RGB:
break;
case NODE_COMBSEP_COLOR_HSV:
convert = create_node("hsvtorgb", NodeItem::Type::Color3);
convert.set_input("in", combine);
break;
case NODE_COMBSEP_COLOR_HSL:
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported color model, using HSV instead: %d", mode);
convert = create_node("hsvtorgb", NodeItem::Type::Color3);
convert.set_input("in", combine);
break;
default:
BLI_assert_unreachable();
}
NodeItem res = convert ? convert : combine;
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,28 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem SeparateXYZNodeParser::compute()
{
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.extract(index);
}
NodeItem CombineXYZNodeParser::compute()
{
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);
NodeItem res = create_node("combine3", NodeItem::Type::Vector3);
res.set_input("in1", x);
res.set_input("in2", y);
res.set_input("in3", z);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem SubsurfaceScatteringNodeParser::compute()
{
/* TODO: implement */
return empty();
}
} // namespace blender::nodes::materialx

View File

@ -1,28 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem TexCheckerNodeParser::compute()
{
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.extract(0).floor() + vector.extract(1).floor())
.if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2);
}
} // namespace blender::nodes::materialx

View File

@ -1,61 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
#include "hydra/image.h"
#include "DEG_depsgraph_query.h"
namespace blender::nodes::materialx {
NodeItem TexEnvironmentNodeParser::compute()
{
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);
Scene *scene = DEG_get_input_scene(depsgraph_);
Main *bmain = DEG_get_bmain(depsgraph_);
/* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains
* pretty general code, so could be moved from bf_usd project. */
std::string image_path = io::hydra::cache_or_get_image_file(
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;
}
} // namespace blender::nodes::materialx

View File

@ -1,81 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
#include "hydra/image.h"
#include "DEG_depsgraph_query.h"
namespace blender::nodes::materialx {
NodeItem TexImageNodeParser::compute()
{
NodeItem 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);
Scene *scene = DEG_get_input_scene(depsgraph_);
Main *bmain = DEG_get_bmain(depsgraph_);
/* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains
* pretty general code, so could be moved from bf_usd project. */
std::string image_path = io::hydra::cache_or_get_image_file(
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);
res.set_input("file", image_path, NodeItem::Type::Filename);
res.set_input("texcoord", vector);
res.set_input("filtertype", val(filtertype));
res.set_input("uaddressmode", val(addressmode));
res.set_input("vaddressmode", val(addressmode));
}
if (STREQ(socket_out_->name, "Alpha")) {
res = res.extract(3);
}
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,29 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem TexNoiseNodeParser::compute()
{
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
NodeItem detail = get_input_value("Detail", NodeItem::Type::Float);
NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float);
if (detail.value && detail.type() == NodeItem::Type::Float) {
detail = val(int(detail.value->asA<float>()));
}
NodeItem position = create_node("position", NodeItem::Type::Vector3);
position = position * scale;
NodeItem res = create_node("fractal3d", NodeItem::Type::Color3);
res.set_input("position", position);
res.set_input("octaves", detail);
res.set_input("lacunarity", lacunarity);
return res;
}
} // namespace blender::nodes::materialx

View File

@ -1,122 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../material.h"
#include "node_parser.h"
namespace blender::nodes::materialx {
NodeItem VectorMathNodeParser::compute()
{
/* TODO: finish some math operations */
auto op = node_->custom1;
NodeItem res = empty();
/* Single operand operations */
NodeItem x = get_input_value(0, NodeItem::Type::Any);
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::Any);
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::Any);
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;
}
} // namespace blender::nodes::materialx

View File

@ -22,6 +22,8 @@
#include "node_shader_register.hh" #include "node_shader_register.hh"
#include "materialx/node_parser.h"
struct bContext; struct bContext;
typedef struct bContext bContext; typedef struct bContext bContext;
struct bNodeExecContext; struct bNodeExecContext;

View File

@ -22,6 +22,41 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_add_shader", in, out); return GPU_stack_link(mat, node, "node_add_shader", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem res = empty();
switch (to_type_) {
case NodeItem::Type::BSDF:
case NodeItem::Type::EDF: {
NodeItem shader1 = get_input_link(0, to_type_);
NodeItem shader2 = get_input_link(1, to_type_);
if (shader1 && !shader2) {
res = shader1;
}
else if (!shader1 && shader2) {
res = shader2;
}
else if (shader1 && shader2) {
res = shader1 + shader2;
}
break;
}
case NodeItem::Type::SurfaceShader: {
/* SurfaceShaders can't be added, returning the first one connected */
res = get_input_link(0, to_type_);
if (!res) {
res = get_input_link(1, to_type_);
}
break;
}
default:
BLI_assert_unreachable();
}
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_add_shader_cc } // namespace blender::nodes::node_shader_add_shader_cc
/* node type definition */ /* node type definition */

View File

@ -31,6 +31,20 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer)); return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer));
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* 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; */
return empty();
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_blackbody_cc } // namespace blender::nodes::node_shader_blackbody_cc
/* node type definition */ /* node type definition */
@ -44,6 +58,7 @@ void register_node_type_sh_blackbody()
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
ntype.gpu_fn = file_ns::node_shader_gpu_blackbody; ntype.gpu_fn = file_ns::node_shader_gpu_blackbody;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -23,6 +23,17 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat,
return GPU_stack_link(mat, node, "brightness_contrast", in, out); return GPU_stack_link(mat, node, "brightness_contrast", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
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));
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_brightness_cc } // namespace blender::nodes::node_shader_brightness_cc
void register_node_type_sh_brightcontrast() void register_node_type_sh_brightcontrast()
@ -34,6 +45,7 @@ void register_node_type_sh_brightcontrast()
sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Brightness/Contrast", NODE_CLASS_OP_COLOR); sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Brightness/Contrast", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::gpu_shader_brightcontrast; ntype.gpu_fn = file_ns::gpu_shader_brightcontrast;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -34,6 +34,26 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out); return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
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);
NodeItem res = create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF);
res.set_input("color", color);
res.set_input("roughness", roughness);
if (normal) {
res.set_input("normal", normal);
}
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_bsdf_diffuse_cc } // namespace blender::nodes::node_shader_bsdf_diffuse_cc
/* node type definition */ /* node type definition */
@ -48,6 +68,7 @@ void register_node_type_sh_bsdf_diffuse()
ntype.add_ui_poll = object_shader_nodes_poll; ntype.add_ui_poll = object_shader_nodes_poll;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_diffuse; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_diffuse;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -253,6 +253,99 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
} }
} }
NODE_SHADER_MATERIALX_BEGIN
{
if (to_type_ != NodeItem::Type::SurfaceShader) {
/* TODO: implement for BSDF and EDF */
return empty();
}
NodeItem base_color = get_input_value("Base Color", NodeItem::Type::Color3);
NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float);
NodeItem subsurface_radius = get_input_value("Subsurface Radius", NodeItem::Type::Color3);
NodeItem subsurface_color = get_input_value("Subsurface Color", NodeItem::Type::Color3);
NodeItem metallic = get_input_value("Metallic", NodeItem::Type::Float);
NodeItem specular = get_input_value("Specular", NodeItem::Type::Float);
// NodeItem specular_tint = get_input_value("Specular Tint");
NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Float);
/* TODO: use Specular Tint input */
NodeItem anisotropic = get_input_value("Anisotropic", NodeItem::Type::Float);
NodeItem anisotropic_rotation = get_input_value("Anisotropic Rotation", NodeItem::Type::Float);
// anisotropic_rotation = 0.5 - (anisotropic_rotation % 1.0)
NodeItem sheen = get_input_value("Sheen", NodeItem::Type::Float);
// sheen_tint = get_input_value("Sheen Tint");
NodeItem clearcoat = get_input_value("Clearcoat", NodeItem::Type::Float);
NodeItem clearcoat_roughness = get_input_value("Clearcoat Roughness", NodeItem::Type::Float);
NodeItem ior = get_input_value("IOR", NodeItem::Type::Float);
NodeItem transmission = get_input_value("Transmission", NodeItem::Type::Float);
NodeItem emission = get_input_value("Emission", NodeItem::Type::Color3);
NodeItem emission_strength = get_input_value("Emission Strength", NodeItem::Type::Float);
NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float);
// transparency = 1.0 - alpha
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3);
NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3);
/* Creating standard_surface */
NodeItem res = create_node("standard_surface", NodeItem::Type::SurfaceShader);
res.set_input("base", val(1.0f));
res.set_input("base_color", base_color);
res.set_input("diffuse_roughness", roughness);
if (normal) {
res.set_input("normal", normal);
}
if (tangent) {
res.set_input("tangent", tangent);
}
res.set_input("metalness", metallic);
res.set_input("specular", specular);
res.set_input("specular_color", base_color);
res.set_input("specular_roughness", roughness);
res.set_input("specular_IOR", ior);
res.set_input("specular_anisotropy", anisotropic);
res.set_input("specular_rotation", anisotropic_rotation);
res.set_input("transmission", transmission);
res.set_input("transmission_color", base_color);
res.set_input("transmission_extra_roughness", roughness);
res.set_input("subsurface", subsurface);
res.set_input("subsurface_color", subsurface_color);
res.set_input("subsurface_radius", subsurface_radius);
res.set_input("subsurface_anisotropy", anisotropic);
res.set_input("sheen", sheen);
res.set_input("sheen_color", base_color);
res.set_input("sheen_roughness", roughness);
res.set_input("coat", clearcoat);
res.set_input("coat_color", base_color);
res.set_input("coat_roughness", clearcoat_roughness);
res.set_input("coat_IOR", ior);
res.set_input("coat_anisotropy", anisotropic);
res.set_input("coat_rotation", anisotropic_rotation);
if (clearcoat_normal) {
res.set_input("coat_normal", clearcoat_normal);
}
res.set_input("emission", emission_strength);
res.set_input("emission_color", emission);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_bsdf_principled_cc } // namespace blender::nodes::node_shader_bsdf_principled_cc
/* node type definition */ /* node type definition */
@ -270,6 +363,7 @@ void register_node_type_sh_bsdf_principled()
ntype.initfunc = file_ns::node_shader_init_principled; ntype.initfunc = file_ns::node_shader_init_principled;
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_principled; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_principled;
ntype.updatefunc = file_ns::node_shader_update_principled; ntype.updatefunc = file_ns::node_shader_update_principled;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -70,6 +70,25 @@ static void sh_node_clamp_build_multi_function(NodeMultiFunctionBuilder &builder
} }
} }
NODE_SHADER_MATERIALX_BEGIN
{
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;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_clamp_cc } // namespace blender::nodes::node_shader_clamp_cc
void register_node_type_sh_clamp() void register_node_type_sh_clamp()
@ -84,6 +103,7 @@ void register_node_type_sh_clamp()
ntype.initfunc = file_ns::node_shader_init_clamp; ntype.initfunc = file_ns::node_shader_init_clamp;
ntype.gpu_fn = file_ns::gpu_shader_clamp; ntype.gpu_fn = file_ns::gpu_shader_clamp;
ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function; ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -136,6 +136,13 @@ static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilde
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band); builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* TODO: Implement */
return empty();
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_color_ramp_cc } // namespace blender::nodes::node_shader_color_ramp_cc
void register_node_type_sh_valtorgb() void register_node_type_sh_valtorgb()
@ -151,6 +158,7 @@ void register_node_type_sh_valtorgb()
node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage); node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::gpu_shader_valtorgb; ntype.gpu_fn = file_ns::gpu_shader_valtorgb;
ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function; ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -16,7 +16,7 @@
#include "node_util.hh" #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) static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{ {
@ -109,11 +109,18 @@ static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &bui
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap); builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
} }
} // namespace blender::nodes::node_shader_curves_cc NODE_SHADER_MATERIALX_BEGIN
{
/* TODO: implement */
return get_input_value("Value", NodeItem::Type::Vector3);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_curves_cc::vec
void register_node_type_sh_curve_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; static bNodeType ntype;
@ -124,13 +131,14 @@ void register_node_type_sh_curve_vec()
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
ntype.gpu_fn = file_ns::gpu_shader_curve_vec; ntype.gpu_fn = file_ns::gpu_shader_curve_vec;
ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function; ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }
/* **************** CURVE RGB ******************** */ /* **************** 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) static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
{ {
@ -251,11 +259,18 @@ static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &bui
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap); builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
} }
} // namespace blender::nodes::node_shader_curves_cc NODE_SHADER_MATERIALX_BEGIN
{
/* TODO: implement */
return get_input_value("Color", NodeItem::Type::Color4);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_curves_cc::rgb
void register_node_type_sh_curve_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; static bNodeType ntype;
@ -266,13 +281,14 @@ void register_node_type_sh_curve_rgb()
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
ntype.gpu_fn = file_ns::gpu_shader_curve_rgb; ntype.gpu_fn = file_ns::gpu_shader_curve_rgb;
ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function; ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }
/* **************** CURVE FLOAT ******************** */ /* **************** 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) static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
{ {
@ -369,11 +385,18 @@ static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &b
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap); builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
} }
} // namespace blender::nodes::node_shader_curves_cc NODE_SHADER_MATERIALX_BEGIN
{
/* TODO: implement */
return get_input_value("Value", NodeItem::Type::Float);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_curves_cc::flt
void register_node_type_sh_curve_float() 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; static bNodeType ntype;
@ -384,6 +407,7 @@ void register_node_type_sh_curve_float()
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
ntype.gpu_fn = file_ns::gpu_shader_curve_float; ntype.gpu_fn = file_ns::gpu_shader_curve_float;
ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function; ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -24,6 +24,21 @@ static int node_shader_gpu_emission(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_emission", in, out); return GPU_stack_link(mat, node, "node_emission", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
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);
NodeItem res = create_node("uniform_edf", NodeItem::Type::EDF);
res.set_input("color", color * strength);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_emission_cc } // namespace blender::nodes::node_shader_emission_cc
/* node type definition */ /* 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); sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER);
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_emission; ntype.gpu_fn = file_ns::node_shader_gpu_emission;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -22,6 +22,13 @@ static int node_shader_gpu_gamma(GPUMaterial *mat,
{ {
return GPU_stack_link(mat, node, "node_gamma", in, out); return GPU_stack_link(mat, node, "node_gamma", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem color = get_input_value("Color", NodeItem::Type::Color4);
NodeItem gamma = get_input_value("Gamma", NodeItem::Type::Float);
return color ^ gamma;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_gamma_cc } // namespace blender::nodes::node_shader_gamma_cc
@ -34,6 +41,7 @@ void register_node_type_sh_gamma()
sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR); sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_gamma; ntype.gpu_fn = file_ns::node_shader_gpu_gamma;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -30,6 +30,30 @@ static int gpu_shader_hue_sat(GPUMaterial *mat,
return GPU_stack_link(mat, node, "hue_sat", in, out); return GPU_stack_link(mat, node, "hue_sat", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* 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);
combine.set_input("in1", hue);
combine.set_input("in2", saturation);
combine.set_input("in3", value);
NodeItem res = create_node("hsvadjust", NodeItem::Type::Color3);
res.set_input("in", color);
res.set_input("amount", combine);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_hueSatVal_cc } // namespace blender::nodes::node_shader_hueSatVal_cc
void register_node_type_sh_hue_sat() void register_node_type_sh_hue_sat()
@ -42,6 +66,7 @@ void register_node_type_sh_hue_sat()
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
ntype.gpu_fn = file_ns::gpu_shader_hue_sat; ntype.gpu_fn = file_ns::gpu_shader_hue_sat;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -26,6 +26,14 @@ static int gpu_shader_invert(GPUMaterial *mat,
return GPU_stack_link(mat, node, "invert", in, out); return GPU_stack_link(mat, node, "invert", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem fac = get_input_value("Fac", NodeItem::Type::Float);
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
return fac.blend(color, fac.val(1.0f) - color);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_invert_cc } // namespace blender::nodes::node_shader_invert_cc
void register_node_type_sh_invert() void register_node_type_sh_invert()
@ -37,6 +45,7 @@ void register_node_type_sh_invert()
sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::gpu_shader_invert; ntype.gpu_fn = file_ns::gpu_shader_invert;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -24,6 +24,17 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_light_falloff", in, out); return GPU_stack_link(mat, node, "node_light_falloff", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
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 * val(1.0f) / (smooth + val(1.0f));
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_light_falloff_cc } // namespace blender::nodes::node_shader_light_falloff_cc
/* node type definition */ /* node type definition */
@ -37,6 +48,7 @@ void register_node_type_sh_light_falloff()
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE); blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
ntype.gpu_fn = file_ns::node_shader_gpu_light_falloff; ntype.gpu_fn = file_ns::node_shader_gpu_light_falloff;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -32,6 +32,19 @@ static int node_shader_gpu_light_path(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_light_path", in, out); return GPU_stack_link(mat, node, "node_light_path", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* 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);
}
return val(0.0f);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_light_path_cc } // namespace blender::nodes::node_shader_light_path_cc
/* node type definition */ /* node type definition */
@ -44,6 +57,7 @@ void register_node_type_sh_light_path()
sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT); sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_light_path; ntype.gpu_fn = file_ns::node_shader_gpu_light_path;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -442,6 +442,49 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui
} }
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* 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();
}
NodeItem res = create_node("range", type);
res.set_input("in", value);
res.set_input("inlow", from_min);
res.set_input("inhigh", from_max);
res.set_input("outlow", to_min);
res.set_input("outhigh", to_max);
res.set_input("doclamp", val(bool(map_range->clamp)));
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_map_range_cc } // namespace blender::nodes::node_shader_map_range_cc
void register_node_type_sh_map_range() void register_node_type_sh_map_range()
@ -461,5 +504,6 @@ void register_node_type_sh_map_range()
ntype.gpu_fn = file_ns::gpu_shader_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.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.gather_link_search_ops = file_ns::node_map_range_gather_link_searches;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -177,6 +177,170 @@ static void sh_node_math_build_multi_function(NodeMultiFunctionBuilder &builder)
} }
} }
NODE_SHADER_MATERIALX_BEGIN
{
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;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_math_cc } // namespace blender::nodes::node_shader_math_cc
void register_node_type_sh_math() void register_node_type_sh_math()
@ -192,6 +356,7 @@ void register_node_type_sh_math()
ntype.updatefunc = node_math_update; ntype.updatefunc = node_math_update;
ntype.build_multi_function = file_ns::sh_node_math_build_multi_function; 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.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -150,6 +150,13 @@ static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &build
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type); builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* TODO: Implement */
return empty();
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_mix_rgb_cc } // namespace blender::nodes::node_shader_mix_rgb_cc
void register_node_type_sh_mix_rgb() void register_node_type_sh_mix_rgb()
@ -165,5 +172,6 @@ void register_node_type_sh_mix_rgb()
ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function; ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
ntype.gather_link_search_ops = nullptr; ntype.gather_link_search_ops = nullptr;
ntype.gather_add_node_search_ops = nullptr; ntype.gather_add_node_search_ops = nullptr;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -23,6 +23,45 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_mix_shader", in, out); return GPU_stack_link(mat, node, "node_mix_shader", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem res = empty();
switch (to_type_) {
case NodeItem::Type::BSDF:
case NodeItem::Type::EDF: {
NodeItem fac = get_input_value(0, NodeItem::Type::Float);
NodeItem shader1 = get_input_link(1, to_type_);
NodeItem shader2 = get_input_link(2, to_type_);
if (shader1 && !shader2) {
res = shader1 * (val(1.0f) - fac);
}
else if (!shader1 && shader2) {
res = shader2 * fac;
}
else if (shader1 && shader2) {
res = create_node("mix", to_type_);
res.set_input("fg", shader1);
res.set_input("bg", shader2);
res.set_input("mix", fac);
}
break;
}
case NodeItem::Type::SurfaceShader: {
/* SurfaceShaders can't be mixed, returning the first one connected */
res = get_input_link(1, NodeItem::Type::SurfaceShader);
if (!res) {
res = get_input_link(2, NodeItem::Type::SurfaceShader);
}
break;
}
default:
BLI_assert_unreachable();
}
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_mix_shader_cc } // namespace blender::nodes::node_shader_mix_shader_cc
/* node type definition */ /* node type definition */
@ -35,6 +74,7 @@ void register_node_type_sh_mix_shader()
sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER); sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER);
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_mix_shader; ntype.gpu_fn = file_ns::node_shader_gpu_mix_shader;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -122,6 +122,38 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
return true; return true;
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeShaderNormalMap *normal_map_node = static_cast<NodeShaderNormalMap *>(node_->storage);
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
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();
}
NodeItem res = create_node("normalmap", NodeItem::Type::Vector3);
res.set_input("in", color);
res.set_input("scale", strength);
res.set_input("space", val(space));
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_normal_map_cc } // namespace blender::nodes::node_shader_normal_map_cc
/* node type definition */ /* node type definition */
@ -139,6 +171,7 @@ void register_node_type_sh_normal_map()
node_type_storage( node_type_storage(
&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage); &ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::gpu_shader_normal_map; ntype.gpu_fn = file_ns::gpu_shader_normal_map;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -43,6 +43,29 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
return true; return true;
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem bsdf = get_input_link("Surface", NodeItem::Type::BSDF);
NodeItem edf = get_input_link("Surface", NodeItem::Type::EDF);
NodeItem surface = empty();
if (bsdf || edf) {
surface = create_node("surface", NodeItem::Type::SurfaceShader);
if (bsdf) {
surface.set_input("bsdf", bsdf);
}
if (edf) {
surface.set_input("edf", edf);
}
}
else {
surface = get_input_link("Surface", NodeItem::Type::SurfaceShader);
}
NodeItem res = create_node("surfacematerial", NodeItem::Type::Material);
res.set_input("surfaceshader", surface);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_output_material_cc } // namespace blender::nodes::node_shader_output_material_cc
/* node type definition */ /* node type definition */
@ -56,6 +79,7 @@ void register_node_type_sh_output_material()
ntype.declare = file_ns::node_declare; ntype.declare = file_ns::node_declare;
ntype.add_ui_poll = object_shader_nodes_poll; ntype.add_ui_poll = object_shader_nodes_poll;
ntype.gpu_fn = file_ns::node_shader_gpu_output_material; ntype.gpu_fn = file_ns::node_shader_gpu_output_material;
ntype.materialx_fn = file_ns::node_shader_materialx;
ntype.no_muting = true; ntype.no_muting = true;

View File

@ -27,6 +27,16 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
return GPU_stack_link(mat, node, "rgbtobw", in, out); return GPU_stack_link(mat, node, "rgbtobw", in, out);
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem color = get_input_value("Color", NodeItem::Type::Color4);
NodeItem res = create_node("luminance", NodeItem::Type::Color4);
res.set_input("in", color);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_rgb_to_bw_cc } // namespace blender::nodes::node_shader_rgb_to_bw_cc
void register_node_type_sh_rgbtobw() void register_node_type_sh_rgbtobw()
@ -38,6 +48,7 @@ void register_node_type_sh_rgbtobw()
sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER); sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_rgbtobw_declare; ntype.declare = file_ns::sh_node_rgbtobw_declare;
ntype.gpu_fn = file_ns::gpu_shader_rgbtobw; ntype.gpu_fn = file_ns::gpu_shader_rgbtobw;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -68,6 +68,31 @@ static int gpu_shader_sepcolor(GPUMaterial *mat,
return 0; return 0;
} }
NODE_SHADER_MATERIALX_BEGIN
{
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);
convert.set_input("in", color);
break;
default:
BLI_assert_unreachable();
}
int index = STREQ(socket_out_->name, "Red") ? 0 : STREQ(socket_out_->name, "Green") ? 1 : 2;
return convert.extract(index);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_separate_color_cc } // namespace blender::nodes::node_shader_separate_color_cc
void register_node_type_sh_sepcolor() void register_node_type_sh_sepcolor()
@ -83,6 +108,7 @@ void register_node_type_sh_sepcolor()
node_type_storage( node_type_storage(
&ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage); &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::gpu_shader_sepcolor; ntype.gpu_fn = file_ns::gpu_shader_sepcolor;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }
@ -136,6 +162,36 @@ static int gpu_shader_combcolor(GPUMaterial *mat,
return 0; return 0;
} }
NODE_SHADER_MATERIALX_BEGIN
{
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;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_combine_color_cc } // namespace blender::nodes::node_shader_combine_color_cc
void register_node_type_sh_combcolor() void register_node_type_sh_combcolor()
@ -151,6 +207,7 @@ void register_node_type_sh_combcolor()
node_type_storage( node_type_storage(
&ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage); &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::gpu_shader_combcolor; ntype.gpu_fn = file_ns::gpu_shader_combcolor;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -12,7 +12,7 @@
#include "NOD_multi_function.hh" #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) static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
{ {
@ -90,11 +90,19 @@ static void sh_node_sepxyz_build_multi_function(NodeMultiFunctionBuilder &builde
builder.set_matching_fn(separate_fn); builder.set_matching_fn(separate_fn);
} }
} // namespace blender::nodes::node_shader_sepcomb_xyz_cc NODE_SHADER_MATERIALX_BEGIN
{
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.extract(index);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_sepcomb_xyz_cc::sep
void register_node_type_sh_sepxyz() 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; static bNodeType ntype;
@ -102,11 +110,12 @@ void register_node_type_sh_sepxyz()
ntype.declare = file_ns::sh_node_sepxyz_declare; ntype.declare = file_ns::sh_node_sepxyz_declare;
ntype.gpu_fn = file_ns::gpu_shader_sepxyz; ntype.gpu_fn = file_ns::gpu_shader_sepxyz;
ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function; ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); 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) static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
{ {
@ -135,11 +144,25 @@ static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &build
builder.set_matching_fn(fn); builder.set_matching_fn(fn);
} }
} // namespace blender::nodes::node_shader_sepcomb_xyz_cc NODE_SHADER_MATERIALX_BEGIN
{
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);
NodeItem res = create_node("combine3", NodeItem::Type::Vector3);
res.set_input("in1", x);
res.set_input("in2", y);
res.set_input("in3", z);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_sepcomb_xyz_cc::comb
void register_node_type_sh_combxyz() 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; static bNodeType ntype;
@ -147,6 +170,7 @@ void register_node_type_sh_combxyz()
ntype.declare = file_ns::sh_node_combxyz_declare; ntype.declare = file_ns::sh_node_combxyz_declare;
ntype.gpu_fn = file_ns::gpu_shader_combxyz; ntype.gpu_fn = file_ns::gpu_shader_combxyz;
ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function; ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -102,6 +102,26 @@ static void sh_node_tex_checker_build_multi_function(NodeMultiFunctionBuilder &b
builder.set_matching_fn(fn); builder.set_matching_fn(fn);
} }
NODE_SHADER_MATERIALX_BEGIN
{
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.extract(0).floor() + vector.extract(1).floor())
.if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2);
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_tex_checker_cc } // namespace blender::nodes::node_shader_tex_checker_cc
void register_node_type_sh_tex_checker() void register_node_type_sh_tex_checker()
@ -117,6 +137,7 @@ void register_node_type_sh_tex_checker()
&ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage); &ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::node_shader_gpu_tex_checker; ntype.gpu_fn = file_ns::node_shader_gpu_tex_checker;
ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function; ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -127,6 +127,13 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
return true; return true;
} }
NODE_SHADER_MATERIALX_BEGIN
{
/* TODO: Implement */
return empty();
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_tex_environment_cc } // namespace blender::nodes::node_shader_tex_environment_cc
/* node type definition */ /* node type definition */
@ -144,6 +151,7 @@ void register_node_type_sh_tex_environment()
ntype.gpu_fn = file_ns::node_shader_gpu_tex_environment; ntype.gpu_fn = file_ns::node_shader_gpu_tex_environment;
ntype.labelfunc = node_image_label; ntype.labelfunc = node_image_label;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE); blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE);
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -11,6 +11,10 @@
#include "IMB_colormanagement.h" #include "IMB_colormanagement.h"
#include "hydra/image.h"
#include "DEG_depsgraph_query.h"
namespace blender::nodes::node_shader_tex_image_cc { namespace blender::nodes::node_shader_tex_image_cc {
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b) static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
@ -172,6 +176,75 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
return true; return true;
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem 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);
Scene *scene = DEG_get_input_scene(depsgraph_);
Main *bmain = DEG_get_bmain(depsgraph_);
/* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains
* pretty general code, so could be moved from bf_usd project. */
std::string image_path = io::hydra::cache_or_get_image_file(
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);
res.set_input("file", image_path, NodeItem::Type::Filename);
res.set_input("texcoord", vector);
res.set_input("filtertype", val(filtertype));
res.set_input("uaddressmode", val(addressmode));
res.set_input("vaddressmode", val(addressmode));
}
if (STREQ(socket_out_->name, "Alpha")) {
res = res.extract(3);
}
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_tex_image_cc } // namespace blender::nodes::node_shader_tex_image_cc
void register_node_type_sh_tex_image() void register_node_type_sh_tex_image()
@ -188,6 +261,7 @@ void register_node_type_sh_tex_image()
ntype.gpu_fn = file_ns::node_shader_gpu_tex_image; ntype.gpu_fn = file_ns::node_shader_gpu_tex_image;
ntype.labelfunc = node_image_label; ntype.labelfunc = node_image_label;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE); blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE);
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -257,6 +257,25 @@ static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder
builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions, storage.normalize); builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions, storage.normalize);
} }
NODE_SHADER_MATERIALX_BEGIN
{
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
NodeItem detail = get_input_value("Detail", NodeItem::Type::Float);
NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float);
NodeItem position = create_node("position", NodeItem::Type::Vector3);
position = position * scale;
NodeItem res = create_node("fractal3d", NodeItem::Type::Color3);
res.set_input("position", position);
if (detail.value) {
res.set_input("octaves", val(int(detail.value->asA<float>())));
}
res.set_input("lacunarity", lacunarity);
return res;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_tex_noise_cc } // namespace blender::nodes::node_shader_tex_noise_cc
void register_node_type_sh_tex_noise() void register_node_type_sh_tex_noise()
@ -274,6 +293,7 @@ void register_node_type_sh_tex_noise()
ntype.gpu_fn = file_ns::node_shader_gpu_tex_noise; ntype.gpu_fn = file_ns::node_shader_gpu_tex_noise;
ntype.updatefunc = file_ns::node_shader_update_tex_noise; ntype.updatefunc = file_ns::node_shader_update_tex_noise;
ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function; ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }

View File

@ -316,6 +316,121 @@ static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &b
builder.set_matching_fn(fn); builder.set_matching_fn(fn);
} }
NODE_SHADER_MATERIALX_BEGIN
{
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;
}
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_vector_math_cc } // namespace blender::nodes::node_shader_vector_math_cc
void register_node_type_sh_vect_math() void register_node_type_sh_vect_math()
@ -332,6 +447,7 @@ void register_node_type_sh_vect_math()
ntype.updatefunc = file_ns::node_shader_update_vector_math; ntype.updatefunc = file_ns::node_shader_update_vector_math;
ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function; 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.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }