forked from blender/blender
Implement export of Shader BSDF nodes #13
@ -147,18 +147,30 @@ set(LIB
|
||||
if(WITH_MATERIALX)
|
||||
list(APPEND SRC
|
||||
materialx/material.cc
|
||||
materialx/nodes/add_shader.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/emission.cc
|
||||
materialx/nodes/huesatval.cc
|
||||
materialx/nodes/invert.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/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
|
||||
|
@ -17,9 +17,7 @@ namespace blender::nodes::materialx {
|
||||
|
||||
CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader");
|
||||
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
||||
Material *material,
|
||||
const std::string &socket_name)
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material)
|
||||
{
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name);
|
||||
|
||||
@ -27,7 +25,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
||||
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(socket_name);
|
||||
OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute_full();
|
||||
}
|
||||
else {
|
||||
OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default();
|
||||
|
@ -15,8 +15,6 @@ namespace blender::nodes::materialx {
|
||||
|
||||
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
|
||||
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
||||
Material *material,
|
||||
const std::string &socket_name = "Surface");
|
||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material);
|
||||
|
||||
} // namespace blender::nodes::materialx
|
||||
|
42
source/blender/nodes/shader/materialx/nodes/add_shader.cc
Normal file
42
source/blender/nodes/shader/materialx/nodes/add_shader.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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
|
28
source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc
Normal file
28
source/blender/nodes/shader/materialx/nodes/bsdf_diffuse.cc
Normal file
@ -0,0 +1,28 @@
|
||||
/* 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", "BSDF");
|
||||
res.set_input("color", color);
|
||||
res.set_input("roughness", roughness);
|
||||
if (normal) {
|
||||
res.set_input("normal", normal);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
15
source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc
Normal file
15
source/blender/nodes/shader/materialx/nodes/bsdf_glass.cc
Normal file
@ -0,0 +1,15 @@
|
||||
/* 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
|
15
source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc
Normal file
15
source/blender/nodes/shader/materialx/nodes/bsdf_glossy.cc
Normal file
@ -0,0 +1,15 @@
|
||||
/* 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
|
@ -8,6 +8,11 @@ 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);
|
||||
@ -40,9 +45,9 @@ NodeItem BSDFPrincipledNodeParser::compute()
|
||||
NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float);
|
||||
// transparency = 1.0 - alpha
|
||||
|
||||
NodeItem normal = get_input_link("Normal");
|
||||
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal");
|
||||
NodeItem tangent = get_input_link("Tangent");
|
||||
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", "surfaceshader");
|
||||
|
@ -0,0 +1,15 @@
|
||||
/* 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
|
15
source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc
Normal file
15
source/blender/nodes/shader/materialx/nodes/bsdf_sheen.cc
Normal file
@ -0,0 +1,15 @@
|
||||
/* 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
|
15
source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc
Normal file
15
source/blender/nodes/shader/materialx/nodes/bsdf_toon.cc
Normal file
@ -0,0 +1,15 @@
|
||||
/* 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
|
@ -0,0 +1,15 @@
|
||||
/* 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
|
@ -0,0 +1,15 @@
|
||||
/* 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
|
23
source/blender/nodes/shader/materialx/nodes/emission.cc
Normal file
23
source/blender/nodes/shader/materialx/nodes/emission.cc
Normal file
@ -0,0 +1,23 @@
|
||||
/* 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", "EDF");
|
||||
res.set_input("color", color * strength);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
@ -14,7 +14,7 @@ NodeItem MathNodeParser::compute()
|
||||
NodeItem res = empty();
|
||||
|
||||
/* Single operand operations */
|
||||
NodeItem x = get_input_value(0, NodeItem::Type::Empty);
|
||||
NodeItem x = get_input_value(0, NodeItem::Type::Any);
|
||||
switch (op) {
|
||||
case NODE_MATH_SINE:
|
||||
res = x.sin();
|
||||
@ -82,7 +82,7 @@ NodeItem MathNodeParser::compute()
|
||||
|
||||
default: {
|
||||
/* 2-operand operations */
|
||||
NodeItem y = get_input_value(1, NodeItem::Type::Empty);
|
||||
NodeItem y = get_input_value(1, NodeItem::Type::Any);
|
||||
switch (op) {
|
||||
case NODE_MATH_ADD:
|
||||
res = x + y;
|
||||
@ -132,7 +132,7 @@ NodeItem MathNodeParser::compute()
|
||||
|
||||
default: {
|
||||
/* 3-operand operations */
|
||||
NodeItem z = get_input_value(2, NodeItem::Type::Empty);
|
||||
NodeItem z = get_input_value(2, NodeItem::Type::Any);
|
||||
switch (op) {
|
||||
case NODE_MATH_WRAP:
|
||||
CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op);
|
||||
|
46
source/blender/nodes/shader/materialx/nodes/mix_shader.cc
Normal file
46
source/blender/nodes/shader/materialx/nodes/mix_shader.cc
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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 * (value(1.0f) - fac);
|
||||
}
|
||||
else if (!shader1 && shader2) {
|
||||
res = shader2 * fac;
|
||||
}
|
||||
else if (shader1 && shader2) {
|
||||
res = create_node("mix", NodeItem::type(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, shader_type_);
|
||||
if (!res) {
|
||||
res = get_input_shader(2, shader_type_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
@ -12,6 +12,86 @@ namespace blender::nodes::materialx {
|
||||
|
||||
NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
|
||||
|
||||
NodeItem::Type NodeItem::type(const std::string &type_str)
|
||||
{
|
||||
if (type_str == "string") {
|
||||
return Type::String;
|
||||
}
|
||||
if (type_str == "filename") {
|
||||
return Type::Filename;
|
||||
}
|
||||
if (type_str == "integer") {
|
||||
return Type::Integer;
|
||||
}
|
||||
if (type_str == "float") {
|
||||
return Type::Float;
|
||||
}
|
||||
if (type_str == "vector2") {
|
||||
return Type::Vector2;
|
||||
}
|
||||
if (type_str == "vector3") {
|
||||
return Type::Vector3;
|
||||
}
|
||||
if (type_str == "vector4") {
|
||||
return Type::Vector4;
|
||||
}
|
||||
if (type_str == "color3") {
|
||||
return Type::Color3;
|
||||
}
|
||||
if (type_str == "color4") {
|
||||
return Type::Color4;
|
||||
}
|
||||
if (type_str == "BSDF") {
|
||||
return Type::BSDF;
|
||||
}
|
||||
if (type_str == "EDF") {
|
||||
return Type::EDF;
|
||||
}
|
||||
if (type_str == "surfaceshader") {
|
||||
return Type::SurfaceShader;
|
||||
}
|
||||
if (type_str == "material") {
|
||||
return Type::Material;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return Type::Empty;
|
||||
}
|
||||
|
||||
std::string NodeItem::type(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Type::String:
|
||||
return "string";
|
||||
case Type::Filename:
|
||||
return "filename";
|
||||
case Type::Integer:
|
||||
return "integer";
|
||||
case Type::Float:
|
||||
return "float";
|
||||
case Type::Vector2:
|
||||
return "vector2";
|
||||
case Type::Vector3:
|
||||
return "vector3";
|
||||
case Type::Vector4:
|
||||
return "vector4";
|
||||
case Type::Color3:
|
||||
return "color3";
|
||||
case Type::Color4:
|
||||
return "color4";
|
||||
case Type::BSDF:
|
||||
return "BSDF";
|
||||
case Type::EDF:
|
||||
return "EDF";
|
||||
case Type::SurfaceShader:
|
||||
return "surfaceshader";
|
||||
case Type::Material:
|
||||
return "material";
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
NodeItem::operator bool() const
|
||||
{
|
||||
return value || node;
|
||||
@ -19,6 +99,21 @@ NodeItem::operator bool() const
|
||||
|
||||
NodeItem NodeItem::operator+(const NodeItem &other) const
|
||||
{
|
||||
Type type = this->type();
|
||||
if (ELEM(type, Type::BSDF, Type::EDF)) {
|
||||
/* Special case: add BSDF/EDF shaders */
|
||||
NodeItem res = empty();
|
||||
if (other.type() == type) {
|
||||
res.node = graph_->addNode("add", MaterialX::EMPTY_STRING, this->type(type));
|
||||
res.set_input("in1", *this);
|
||||
res.set_input("in2", other);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return arithmetic(other, "add", [](float a, float b) { return a + b; });
|
||||
}
|
||||
|
||||
@ -34,6 +129,22 @@ NodeItem NodeItem::operator-() const
|
||||
|
||||
NodeItem NodeItem::operator*(const NodeItem &other) const
|
||||
{
|
||||
Type type = this->type();
|
||||
if (ELEM(type, Type::BSDF, Type::EDF)) {
|
||||
/* Special case: multiple BSDF/EDF shader by Float or Color3 */
|
||||
NodeItem res = empty();
|
||||
Type other_type = other.type();
|
||||
if (ELEM(other_type, Type::Float, Type::Color3)) {
|
||||
res.node = graph_->addNode("multiply", MaterialX::EMPTY_STRING, this->type(type));
|
||||
res.set_input("in1", *this);
|
||||
res.set_input("in2", other);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return arithmetic(other, "multiply", [](float a, float b) { return a * b; });
|
||||
}
|
||||
|
||||
@ -70,7 +181,7 @@ bool NodeItem::operator==(const NodeItem &other) const
|
||||
|
||||
NodeItem item1 = *this;
|
||||
NodeItem item2 = other;
|
||||
Type to_type = adjust_types(item1, item2);
|
||||
Type to_type = cast_types(item1, item2);
|
||||
if (to_type == Type::Empty) {
|
||||
return false;
|
||||
}
|
||||
@ -248,10 +359,14 @@ NodeItem NodeItem::extract(const int index) const
|
||||
NodeItem NodeItem::convert(Type to_type) const
|
||||
{
|
||||
Type from_type = type();
|
||||
if (from_type == to_type) {
|
||||
if (from_type == Type::Empty || from_type == to_type || to_type == Type::Any) {
|
||||
return *this;
|
||||
}
|
||||
if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) {
|
||||
CLOG_WARN(LOG_MATERIALX_SHADER,
|
||||
"Cannot convert: %s -> %s",
|
||||
type(from_type).c_str(),
|
||||
type(to_type).c_str());
|
||||
return empty();
|
||||
}
|
||||
|
||||
@ -448,7 +563,7 @@ NodeItem NodeItem::if_else(CompareOp op,
|
||||
|
||||
auto item1 = if_val;
|
||||
auto item2 = else_val;
|
||||
Type to_type = adjust_types(item1, item2);
|
||||
Type to_type = cast_types(item1, item2);
|
||||
if (to_type == Type::Empty) {
|
||||
return res;
|
||||
}
|
||||
@ -554,66 +669,12 @@ void NodeItem::add_output(const std::string &name, Type out_type)
|
||||
node->addOutput(name, type(out_type));
|
||||
}
|
||||
|
||||
NodeItem::Type NodeItem::type(const std::string &type_str)
|
||||
{
|
||||
if (type_str == "string") {
|
||||
return Type::String;
|
||||
}
|
||||
if (type_str == "integer") {
|
||||
return Type::Integer;
|
||||
}
|
||||
if (type_str == "float") {
|
||||
return Type::Float;
|
||||
}
|
||||
if (type_str == "vector2") {
|
||||
return Type::Vector2;
|
||||
}
|
||||
if (type_str == "vector3") {
|
||||
return Type::Vector3;
|
||||
}
|
||||
if (type_str == "vector4") {
|
||||
return Type::Vector4;
|
||||
}
|
||||
if (type_str == "color3") {
|
||||
return Type::Color3;
|
||||
}
|
||||
if (type_str == "color4") {
|
||||
return Type::Color4;
|
||||
}
|
||||
return Type::Other;
|
||||
}
|
||||
|
||||
std::string NodeItem::type(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Type::String:
|
||||
return "string";
|
||||
case Type::Integer:
|
||||
return "integer";
|
||||
case Type::Float:
|
||||
return "float";
|
||||
case Type::Vector2:
|
||||
return "vector2";
|
||||
case Type::Vector3:
|
||||
return "vector3";
|
||||
case Type::Vector4:
|
||||
return "vector4";
|
||||
case Type::Color3:
|
||||
return "color3";
|
||||
case Type::Color4:
|
||||
return "color4";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool NodeItem::is_arithmetic(Type type)
|
||||
{
|
||||
return type >= Type::Float;
|
||||
return type >= Type::Float && type <= Type::Color4;
|
||||
}
|
||||
|
||||
NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
|
||||
NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2)
|
||||
{
|
||||
Type t1 = item1.type();
|
||||
Type t2 = item2.type();
|
||||
@ -621,6 +682,8 @@ NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
|
||||
return t1;
|
||||
}
|
||||
if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
|
||||
CLOG_WARN(
|
||||
LOG_MATERIALX_SHADER, "Can't adjust types: %s <-> %s", type(t1).c_str(), type(t2).c_str());
|
||||
return Type::Empty;
|
||||
}
|
||||
if (t1 < t2) {
|
||||
@ -701,7 +764,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
|
||||
NodeItem res = empty();
|
||||
NodeItem item1 = *this;
|
||||
NodeItem item2 = other;
|
||||
Type to_type = adjust_types(item1, item2);
|
||||
Type to_type = cast_types(item1, item2);
|
||||
if (to_type == Type::Empty) {
|
||||
return res;
|
||||
}
|
||||
|
@ -11,16 +11,28 @@ namespace blender::nodes::materialx {
|
||||
class NodeItem {
|
||||
public:
|
||||
enum class Type {
|
||||
Empty = 0,
|
||||
Other, /* For MaterialX types like: surfaceshader, bsdf, edf, ...*/
|
||||
Any = 0,
|
||||
Empty,
|
||||
|
||||
/* Value types */
|
||||
String,
|
||||
Filename,
|
||||
Integer,
|
||||
/* Block of arithmetic types. Ordered by type cast */
|
||||
Float,
|
||||
Vector2,
|
||||
Vector3,
|
||||
Vector4,
|
||||
Color3,
|
||||
Color4
|
||||
Vector4,
|
||||
Color4,
|
||||
/* End of arithmetic types */
|
||||
|
||||
/* Shader types
|
||||
* NOTE: There are only supported types */
|
||||
BSDF,
|
||||
EDF,
|
||||
SurfaceShader,
|
||||
Material,
|
||||
};
|
||||
enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq };
|
||||
|
||||
@ -35,6 +47,9 @@ class NodeItem {
|
||||
NodeItem(MaterialX::GraphElement *graph);
|
||||
~NodeItem() = default;
|
||||
|
||||
static Type type(const std::string &type_str);
|
||||
static std::string type(Type type);
|
||||
|
||||
/* Operators */
|
||||
operator bool() const;
|
||||
NodeItem operator+(const NodeItem &other) const;
|
||||
@ -92,10 +107,8 @@ class NodeItem {
|
||||
void add_output(const std::string &in_name, Type out_type);
|
||||
|
||||
private:
|
||||
static Type type(const std::string &type_str);
|
||||
static std::string type(Type type);
|
||||
static bool is_arithmetic(Type type);
|
||||
static Type adjust_types(NodeItem &item1, NodeItem &item2);
|
||||
static Type cast_types(NodeItem &item1, NodeItem &item2);
|
||||
|
||||
bool is_arithmetic() const;
|
||||
NodeItem arithmetic(const std::string &category, std::function<float(float)> func) const;
|
||||
|
@ -22,11 +22,21 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph,
|
||||
{
|
||||
}
|
||||
|
||||
std::string NodeParser::node_name(const bNode *node, const bNodeSocket *socket_out)
|
||||
NodeItem NodeParser::compute_full()
|
||||
{
|
||||
return MaterialX::createValidName(node->output_sockets().size() <= 1 ?
|
||||
std::string(node->name) :
|
||||
std::string(node->name) + "_" + socket_out->name);
|
||||
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 &mx_category, const std::string &mx_type)
|
||||
@ -36,34 +46,34 @@ NodeItem NodeParser::create_node(const std::string &mx_category, const std::stri
|
||||
return res;
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_default(const std::string &name)
|
||||
NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type)
|
||||
{
|
||||
return get_input_default(node_->input_by_identifier(name));
|
||||
return get_input_default(node_->input_by_identifier(name), to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_default(int index)
|
||||
NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type)
|
||||
{
|
||||
return get_input_default(node_->input_socket(index));
|
||||
return get_input_default(node_->input_socket(index), to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_link(const std::string &name)
|
||||
NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type)
|
||||
{
|
||||
return get_input_link(node_->input_by_identifier(name));
|
||||
return get_input_link(node_->input_by_identifier(name), to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_link(int index)
|
||||
NodeItem NodeParser::get_input_link(int index, NodeItem::Type to_type)
|
||||
{
|
||||
return get_input_link(node_->input_socket(index));
|
||||
return get_input_link(node_->input_socket(index), to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_value(const std::string &name, const NodeItem::Type type)
|
||||
NodeItem NodeParser::get_input_value(const std::string &name, NodeItem::Type to_type)
|
||||
{
|
||||
return get_input_value(node_->input_by_identifier(name), type);
|
||||
return get_input_value(node_->input_by_identifier(name), to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_value(int index, const NodeItem::Type type)
|
||||
NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type)
|
||||
{
|
||||
return get_input_value(node_->input_socket(index), type);
|
||||
return get_input_value(node_->input_socket(index), to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::empty() const
|
||||
@ -71,7 +81,7 @@ NodeItem NodeParser::empty() const
|
||||
return NodeItem(graph_);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_default(const bNodeSocket &socket)
|
||||
NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type)
|
||||
{
|
||||
NodeItem res = empty();
|
||||
switch (socket.type) {
|
||||
@ -96,10 +106,10 @@ NodeItem NodeParser::get_input_default(const bNodeSocket &socket)
|
||||
CLOG_WARN(LOG_MATERIALX_SHADER, "Unsupported socket type: %d", socket.type);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return res.convert(to_type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
|
||||
NodeItem NodeParser::get_input_link(const bNodeSocket &socket, NodeItem::Type to_type)
|
||||
{
|
||||
NodeItem res = empty();
|
||||
|
||||
@ -119,21 +129,16 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
|
||||
from_node = link->fromnode;
|
||||
}
|
||||
|
||||
/* Checking if node was already computed */
|
||||
res.node = graph_->getNode(node_name(from_node, link->fromsock));
|
||||
if (res.node) {
|
||||
return res;
|
||||
}
|
||||
/* Creating required NodeParser object */
|
||||
std::unique_ptr<NodeParser> parser;
|
||||
|
||||
/* Computing from_node with required NodeParser object */
|
||||
#define CASE_NODE_TYPE(type, T) \
|
||||
case type: \
|
||||
res = T(graph_, depsgraph_, material_, from_node, link->fromsock).compute_full(); \
|
||||
parser = std::make_unique<T>(graph_, depsgraph_, material_, from_node, link->fromsock); \
|
||||
break;
|
||||
|
||||
switch (from_node->typeinfo->type) {
|
||||
CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser)
|
||||
CASE_NODE_TYPE(SH_NODE_BSDF_PRINCIPLED, BSDFPrincipledNodeParser)
|
||||
CASE_NODE_TYPE(SH_NODE_COMBINE_COLOR, CombineColorNodeParser)
|
||||
CASE_NODE_TYPE(SH_NODE_COMBXYZ, CombineXYZNodeParser)
|
||||
CASE_NODE_TYPE(SH_NODE_HUE_SAT, HueSatValNodeParser)
|
||||
@ -155,27 +160,137 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
|
||||
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;
|
||||
}
|
||||
|
||||
NodeItem NodeParser::get_input_value(const bNodeSocket &socket, const NodeItem::Type type)
|
||||
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 res = get_input_link(socket);
|
||||
if (!res) {
|
||||
res = get_input_default(socket);
|
||||
}
|
||||
return type == NodeItem::Type::Empty ? res : res.convert(type);
|
||||
}
|
||||
|
||||
NodeItem NodeParser::compute_full()
|
||||
NodeItem ShaderNodeParser::compute_full()
|
||||
{
|
||||
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type);
|
||||
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(node_, socket_out_));
|
||||
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
|
||||
|
@ -31,24 +31,44 @@ class NodeParser {
|
||||
virtual NodeItem compute() = 0;
|
||||
|
||||
protected:
|
||||
static std::string node_name(const bNode *node, const bNodeSocket *socket_out);
|
||||
virtual NodeItem compute_full();
|
||||
virtual std::string node_name();
|
||||
NodeItem create_node(const std::string &mx_category, const std::string &mx_type);
|
||||
NodeItem get_input_default(const std::string &name);
|
||||
NodeItem get_input_default(int index);
|
||||
NodeItem get_input_link(const std::string &name);
|
||||
NodeItem get_input_link(int index);
|
||||
NodeItem get_input_value(const std::string &name,
|
||||
const NodeItem::Type type);
|
||||
NodeItem get_input_value(int index, const 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 value(const T &data) const;
|
||||
|
||||
private:
|
||||
NodeItem get_input_default(const bNodeSocket &socket);
|
||||
NodeItem get_input_link(const bNodeSocket &socket);
|
||||
NodeItem get_input_value(const bNodeSocket &socket,
|
||||
const NodeItem::Type type);
|
||||
NodeItem compute_full();
|
||||
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::value(const T &data) const
|
||||
@ -56,28 +76,48 @@ template<class T> NodeItem NodeParser::value(const T &data) const
|
||||
return empty().val(data);
|
||||
}
|
||||
|
||||
#define DECLARE_PARSER(T) \
|
||||
#define DECLARE_NODE_PARSER(T) \
|
||||
class T : public NodeParser { \
|
||||
public: \
|
||||
using NodeParser::NodeParser; \
|
||||
NodeItem compute() override; \
|
||||
};
|
||||
|
||||
DECLARE_PARSER(BrightContrastNodeParser)
|
||||
DECLARE_PARSER(BSDFPrincipledNodeParser)
|
||||
DECLARE_PARSER(CombineColorNodeParser)
|
||||
DECLARE_PARSER(CombineXYZNodeParser)
|
||||
DECLARE_PARSER(HueSatValNodeParser)
|
||||
DECLARE_PARSER(InvertNodeParser)
|
||||
DECLARE_PARSER(MathNodeParser)
|
||||
DECLARE_PARSER(MixRGBNodeParser)
|
||||
DECLARE_PARSER(NormalMapNodeParser)
|
||||
DECLARE_PARSER(SeparateColorNodeParser)
|
||||
DECLARE_PARSER(SeparateXYZNodeParser)
|
||||
DECLARE_PARSER(TexCheckerNodeParser)
|
||||
DECLARE_PARSER(TexEnvironmentNodeParser)
|
||||
DECLARE_PARSER(TexImageNodeParser)
|
||||
DECLARE_PARSER(TexNoiseNodeParser)
|
||||
DECLARE_PARSER(VectorMathNodeParser)
|
||||
#define DECLARE_SHADER_NODE_PARSER(T) \
|
||||
class T : public ShaderNodeParser { \
|
||||
public: \
|
||||
using ShaderNodeParser::ShaderNodeParser; \
|
||||
NodeItem compute() override; \
|
||||
};
|
||||
|
||||
DECLARE_NODE_PARSER(BrightContrastNodeParser)
|
||||
DECLARE_NODE_PARSER(CombineColorNodeParser)
|
||||
DECLARE_NODE_PARSER(CombineXYZNodeParser)
|
||||
DECLARE_NODE_PARSER(HueSatValNodeParser)
|
||||
DECLARE_NODE_PARSER(InvertNodeParser)
|
||||
DECLARE_NODE_PARSER(MathNodeParser)
|
||||
DECLARE_NODE_PARSER(MixRGBNodeParser)
|
||||
DECLARE_NODE_PARSER(NormalMapNodeParser)
|
||||
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
|
||||
|
@ -9,27 +9,34 @@ OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *grap
|
||||
const Depsgraph *depsgraph,
|
||||
const Material *material,
|
||||
const bNode *node)
|
||||
: NodeParser(graph, depsgraph, material, node, nullptr)
|
||||
: ShaderNodeParser(graph, depsgraph, material, node, nullptr, NodeItem::Type::Material)
|
||||
{
|
||||
}
|
||||
|
||||
NodeItem OutputMaterialNodeParser::compute()
|
||||
{
|
||||
return empty();
|
||||
}
|
||||
|
||||
NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name)
|
||||
{
|
||||
NodeItem surface = empty();
|
||||
if (node_) {
|
||||
surface = get_input_link(socket_name);
|
||||
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", "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", "surfaceshader");
|
||||
surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
|
||||
}
|
||||
NodeItem res = create_node("surfacematerial", "material");
|
||||
res.node->setName(node_name(node_, nullptr));
|
||||
res.set_input("surfaceshader", surface);
|
||||
return res;
|
||||
}
|
||||
@ -55,4 +62,9 @@ NodeItem OutputMaterialNodeParser::compute_default()
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string OutputMaterialNodeParser::node_name()
|
||||
{
|
||||
return NodeParser::node_name();
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::materialx
|
||||
|
@ -8,15 +8,19 @@
|
||||
|
||||
namespace blender::nodes::materialx {
|
||||
|
||||
class OutputMaterialNodeParser : public NodeParser {
|
||||
class OutputMaterialNodeParser : public ShaderNodeParser {
|
||||
public:
|
||||
OutputMaterialNodeParser(MaterialX::GraphElement *graph,
|
||||
const Depsgraph *depsgraph,
|
||||
const Material *material,
|
||||
const bNode *node);
|
||||
NodeItem compute() override;
|
||||
NodeItem compute(const std::string &socket_name);
|
||||
|
||||
using ShaderNodeParser::compute_full;
|
||||
NodeItem compute_default();
|
||||
|
||||
protected:
|
||||
std::string node_name() override;
|
||||
};
|
||||
|
||||
} // namespace blender::nodes::materialx
|
||||
|
@ -0,0 +1,15 @@
|
||||
/* 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
|
@ -8,7 +8,7 @@ namespace blender::nodes::materialx {
|
||||
|
||||
NodeItem TexCheckerNodeParser::compute()
|
||||
{
|
||||
NodeItem vector = get_input_link("Vector");
|
||||
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2);
|
||||
NodeItem color1 = get_input_value("Color1", NodeItem::Type::Color3);
|
||||
NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3);
|
||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
||||
@ -16,28 +16,13 @@ NodeItem TexCheckerNodeParser::compute()
|
||||
if (!vector) {
|
||||
vector = create_node("texcoord", "vector2");
|
||||
}
|
||||
vector = vector * scale;
|
||||
|
||||
NodeItem separate = create_node("separate2", "multioutput");
|
||||
separate.set_input("in", vector);
|
||||
separate.add_output("outx", NodeItem::Type::Float);
|
||||
separate.add_output("outy", NodeItem::Type::Float);
|
||||
|
||||
NodeItem modulo_x = create_node("modulo", "float");
|
||||
modulo_x.set_input("in1", separate, "outx");
|
||||
modulo_x.set_input("in2", value(2.0f));
|
||||
|
||||
NodeItem modulo_y = create_node("modulo", "float");
|
||||
modulo_y.set_input("in1", separate, "outy");
|
||||
modulo_y.set_input("in2", value(2.0f));
|
||||
|
||||
NodeItem ifequal = (modulo_x.floor() + modulo_y.floor())
|
||||
.if_else(NodeItem::CompareOp::Eq, value(1.0f), value(0.0f), value(1.0f));
|
||||
|
||||
vector = (vector * scale) % value(2.0f);
|
||||
NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor())
|
||||
.if_else(NodeItem::CompareOp::Eq, value(1.0f), value(1.0f), value(0.0f));
|
||||
NodeItem res = create_node("mix", "color3");
|
||||
res.set_input("bg", color1);
|
||||
res.set_input("fg", color2);
|
||||
res.set_input("mix", ifequal);
|
||||
res.set_input("fg", color1);
|
||||
res.set_input("bg", color2);
|
||||
res.set_input("mix", mix);
|
||||
return res;
|
||||
}
|
||||
|
||||