forked from blender/blender
MaterialX: fix review comments #19
@ -225,6 +225,9 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
|
||||
struct bNodeExecData *execdata,
|
||||
struct GPUNodeStack *in,
|
||||
struct GPUNodeStack *out);
|
||||
typedef void (*NodeMaterialXExecFunction)(void *data,
|
||||
struct bNode *node,
|
||||
struct bNodeSocket *out);
|
||||
|
||||
/**
|
||||
* \brief Defines a node type.
|
||||
@ -339,6 +342,8 @@ typedef struct bNodeType {
|
||||
NodeExecFunction exec_fn;
|
||||
/* gpu */
|
||||
NodeGPUExecFunction gpu_fn;
|
||||
/* MaterialX */
|
||||
NodeMaterialXExecFunction materialx_fn;
|
||||
|
||||
/* Get an instance of this node's compositor operation. Freeing the instance is the
|
||||
* responsibility of the caller. */
|
||||
|
@ -147,44 +147,12 @@ set(LIB
|
||||
if(WITH_MATERIALX)
|
||||
list(APPEND SRC
|
||||
materialx/material.cc
|
||||
materialx/nodes/add_shader.cc
|
||||
materialx/nodes/blackbody.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/node_item.cc
|
||||
materialx/node_parser.cc
|
||||
|
||||
materialx/material.h
|
||||
materialx/nodes/node_item.h
|
||||
materialx/nodes/node_parser.h
|
||||
materialx/nodes/output_material.h
|
||||
materialx/node_item.h
|
||||
materialx/node_parser.h
|
||||
)
|
||||
list(APPEND LIB
|
||||
MaterialXCore
|
||||
|
@ -3,7 +3,7 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "material.h"
|
||||
#include "nodes/output_material.h"
|
||||
#include "node_parser.h"
|
||||
|
||||
#include <MaterialXFormat/XmlIo.h>
|
||||
|
||||
@ -15,7 +15,42 @@
|
||||
|
||||
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)
|
||||
{
|
||||
@ -25,10 +60,21 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *mater
|
||||
if (material->use_nodes) {
|
||||
material->nodetree->ensure_topology_cache();
|
||||
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 {
|
||||
DefaultMaterialNodeParser(
|
||||
doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material)
|
||||
.compute_error();
|
||||
}
|
||||
}
|
||||
else {
|
||||
OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default();
|
||||
DefaultMaterialNodeParser(
|
||||
doc.get(), depsgraph, material, nullptr, nullptr, NodeItem::Type::Material)
|
||||
.compute();
|
||||
}
|
||||
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER,
|
||||
|
@ -6,15 +6,11 @@
|
||||
|
||||
#include <MaterialXCore/Document.h>
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
struct Depsgraph;
|
||||
struct Material;
|
||||
|
||||
namespace blender::nodes::materialx {
|
||||
|
||||
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
|
||||
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material);
|
||||
|
||||
} // namespace blender::nodes::materialx
|
||||
|
@ -3,7 +3,6 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "node_item.h"
|
||||
#include "../material.h"
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_utildefines.h"
|
||||
@ -63,6 +62,8 @@ NodeItem::Type NodeItem::type(const std::string &type_str)
|
||||
std::string NodeItem::type(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Type::Any:
|
||||
return "";
|
||||
case Type::String:
|
||||
return "string";
|
||||
case Type::Filename:
|
@ -53,6 +53,7 @@ class NodeItem {
|
||||
|
||||
static Type type(const std::string &type_str);
|
||||
static std::string type(Type type);
|
||||
static bool is_arithmetic(Type type);
|
||||
|
||||
/* Operators */
|
||||
operator bool() const;
|
||||
@ -112,7 +113,6 @@ class NodeItem {
|
||||
void add_output(const std::string &in_name, Type out_type);
|
||||
|
||||
private:
|
||||
static bool is_arithmetic(Type type);
|
||||
static Type cast_types(NodeItem &item1, NodeItem &item2);
|
||||
|
||||
bool is_arithmetic() const;
|
188
source/blender/nodes/shader/materialx/node_parser.cc
Normal file
188
source/blender/nodes/shader/materialx/node_parser.cc
Normal 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
|
96
source/blender/nodes/shader/materialx/node_parser.h
Normal file
96
source/blender/nodes/shader/materialx/node_parser.h
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include "node_shader_register.hh"
|
||||
|
||||
#include "materialx/node_parser.h"
|
||||
|
||||
struct bContext;
|
||||
typedef struct bContext bContext;
|
||||
struct bNodeExecContext;
|
||||
|
@ -22,6 +22,41 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
@ -44,6 +58,7 @@ void register_node_type_sh_blackbody()
|
||||
ntype.declare = file_ns::node_declare;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_blackbody;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -23,6 +23,17 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
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);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_brightcontrast;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -34,6 +34,26 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
@ -48,6 +68,7 @@ void register_node_type_sh_bsdf_diffuse()
|
||||
ntype.add_ui_poll = object_shader_nodes_poll;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_diffuse;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
/* node type definition */
|
||||
@ -270,6 +363,7 @@ void register_node_type_sh_bsdf_principled()
|
||||
ntype.initfunc = file_ns::node_shader_init_principled;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_principled;
|
||||
ntype.updatefunc = file_ns::node_shader_update_principled;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
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.gpu_fn = file_ns::gpu_shader_clamp;
|
||||
ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -136,6 +136,13 @@ static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilde
|
||||
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
|
||||
|
||||
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);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_valtorgb;
|
||||
ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#include "node_util.hh"
|
||||
|
||||
namespace blender::nodes::node_shader_curves_cc {
|
||||
namespace blender::nodes::node_shader_curves_cc::vec {
|
||||
|
||||
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
@ -109,11 +109,18 @@ static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &bui
|
||||
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_curves_cc
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
/* 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()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_shader_curves_cc;
|
||||
namespace file_ns = blender::nodes::node_shader_curves_cc::vec;
|
||||
|
||||
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);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_curve_vec;
|
||||
ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
/* **************** CURVE RGB ******************** */
|
||||
|
||||
namespace blender::nodes::node_shader_curves_cc {
|
||||
namespace blender::nodes::node_shader_curves_cc::rgb {
|
||||
|
||||
static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
@ -251,11 +259,18 @@ static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &bui
|
||||
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_curves_cc
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
/* 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()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_shader_curves_cc;
|
||||
namespace file_ns = blender::nodes::node_shader_curves_cc::rgb;
|
||||
|
||||
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);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_curve_rgb;
|
||||
ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
/* **************** CURVE FLOAT ******************** */
|
||||
|
||||
namespace blender::nodes::node_shader_curves_cc {
|
||||
namespace blender::nodes::node_shader_curves_cc::flt {
|
||||
|
||||
static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
@ -369,11 +385,18 @@ static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &b
|
||||
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_curves_cc
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
/* 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()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_shader_curves_cc;
|
||||
namespace file_ns = blender::nodes::node_shader_curves_cc::flt;
|
||||
|
||||
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);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_curve_float;
|
||||
ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -24,6 +24,21 @@ static int node_shader_gpu_emission(GPUMaterial *mat,
|
||||
return GPU_stack_link(mat, node, "node_emission", in, out);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
@ -36,6 +51,7 @@ void register_node_type_sh_emission()
|
||||
sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_emission;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -22,6 +22,13 @@ static int node_shader_gpu_gamma(GPUMaterial *mat,
|
||||
{
|
||||
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
|
||||
|
||||
@ -34,6 +41,7 @@ void register_node_type_sh_gamma()
|
||||
sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_gamma;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -30,6 +30,30 @@ static int gpu_shader_hue_sat(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
void register_node_type_sh_hue_sat()
|
||||
@ -42,6 +66,7 @@ void register_node_type_sh_hue_sat()
|
||||
ntype.declare = file_ns::node_declare;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_hue_sat;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -26,6 +26,14 @@ static int gpu_shader_invert(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
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);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_invert;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -24,6 +24,17 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
@ -37,6 +48,7 @@ void register_node_type_sh_light_falloff()
|
||||
ntype.declare = file_ns::node_declare;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::MIDDLE);
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_light_falloff;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -32,6 +32,19 @@ static int node_shader_gpu_light_path(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* 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);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_light_path;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -442,6 +442,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
|
||||
|
||||
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.build_multi_function = file_ns::sh_node_map_range_build_multi_function;
|
||||
ntype.gather_link_search_ops = file_ns::node_map_range_gather_link_searches;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
void register_node_type_sh_math()
|
||||
@ -192,6 +356,7 @@ void register_node_type_sh_math()
|
||||
ntype.updatefunc = node_math_update;
|
||||
ntype.build_multi_function = file_ns::sh_node_math_build_multi_function;
|
||||
ntype.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
/* TODO: Implement */
|
||||
return empty();
|
||||
}
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_mix_rgb_cc
|
||||
|
||||
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.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -23,6 +23,45 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* 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);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_mix_shader;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -122,6 +122,38 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
@ -139,6 +171,7 @@ void register_node_type_sh_normal_map()
|
||||
node_type_storage(
|
||||
&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_normal_map;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -43,6 +43,29 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
/* node type definition */
|
||||
@ -56,6 +79,7 @@ void register_node_type_sh_output_material()
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.add_ui_poll = object_shader_nodes_poll;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_output_material;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
ntype.no_muting = true;
|
||||
|
||||
|
@ -27,6 +27,16 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
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);
|
||||
ntype.declare = file_ns::sh_node_rgbtobw_declare;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_rgbtobw;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -68,6 +68,31 @@ static int gpu_shader_sepcolor(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
void register_node_type_sh_sepcolor()
|
||||
@ -83,6 +108,7 @@ void register_node_type_sh_sepcolor()
|
||||
node_type_storage(
|
||||
&ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_sepcolor;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
@ -136,6 +162,36 @@ static int gpu_shader_combcolor(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
void register_node_type_sh_combcolor()
|
||||
@ -151,6 +207,7 @@ void register_node_type_sh_combcolor()
|
||||
node_type_storage(
|
||||
&ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
|
||||
ntype.gpu_fn = file_ns::gpu_shader_combcolor;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include "NOD_multi_function.hh"
|
||||
|
||||
namespace blender::nodes::node_shader_sepcomb_xyz_cc {
|
||||
namespace blender::nodes::node_shader_sepcomb_xyz_cc::sep {
|
||||
|
||||
static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
@ -90,11 +90,19 @@ static void sh_node_sepxyz_build_multi_function(NodeMultiFunctionBuilder &builde
|
||||
builder.set_matching_fn(separate_fn);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
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()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
|
||||
namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc::sep;
|
||||
|
||||
static bNodeType ntype;
|
||||
|
||||
@ -102,11 +110,12 @@ void register_node_type_sh_sepxyz()
|
||||
ntype.declare = file_ns::sh_node_sepxyz_declare;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_sepxyz;
|
||||
ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
namespace blender::nodes::node_shader_sepcomb_xyz_cc {
|
||||
namespace blender::nodes::node_shader_sepcomb_xyz_cc::comb {
|
||||
|
||||
static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
@ -135,11 +144,25 @@ static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &build
|
||||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
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()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
|
||||
namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc::comb;
|
||||
|
||||
static bNodeType ntype;
|
||||
|
||||
@ -147,6 +170,7 @@ void register_node_type_sh_combxyz()
|
||||
ntype.declare = file_ns::sh_node_combxyz_declare;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_combxyz;
|
||||
ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -102,6 +102,26 @@ static void sh_node_tex_checker_build_multi_function(NodeMultiFunctionBuilder &b
|
||||
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
|
||||
|
||||
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.gpu_fn = file_ns::node_shader_gpu_tex_checker;
|
||||
ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -127,6 +127,13 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
|
||||
return true;
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
/* TODO: Implement */
|
||||
return empty();
|
||||
}
|
||||
NODE_SHADER_MATERIALX_END
|
||||
|
||||
} // namespace blender::nodes::node_shader_tex_environment_cc
|
||||
|
||||
/* 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.labelfunc = node_image_label;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE);
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -11,6 +11,10 @@
|
||||
|
||||
#include "IMB_colormanagement.h"
|
||||
|
||||
#include "hydra/image.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
namespace blender::nodes::node_shader_tex_image_cc {
|
||||
|
||||
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
|
||||
@ -172,6 +176,75 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
|
||||
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
|
||||
|
||||
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.labelfunc = node_image_label;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE);
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -257,6 +257,25 @@ static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder
|
||||
builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions, storage.normalize);
|
||||
}
|
||||
|
||||
NODE_SHADER_MATERIALX_BEGIN
|
||||
{
|
||||
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
|
||||
|
||||
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.updatefunc = file_ns::node_shader_update_tex_noise;
|
||||
ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -316,6 +316,121 @@ static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &b
|
||||
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
|
||||
|
||||
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.build_multi_function = file_ns::sh_node_vector_math_build_multi_function;
|
||||
ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
|
||||
ntype.materialx_fn = file_ns::node_shader_materialx;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user