forked from blender/blender
Implement export of Shader BSDF nodes #13
@ -147,18 +147,30 @@ set(LIB
|
|||||||
if(WITH_MATERIALX)
|
if(WITH_MATERIALX)
|
||||||
list(APPEND SRC
|
list(APPEND SRC
|
||||||
materialx/material.cc
|
materialx/material.cc
|
||||||
|
materialx/nodes/add_shader.cc
|
||||||
materialx/nodes/brightness.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_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/huesatval.cc
|
||||||
materialx/nodes/invert.cc
|
materialx/nodes/invert.cc
|
||||||
materialx/nodes/math.cc
|
materialx/nodes/math.cc
|
||||||
materialx/nodes/mix_rgb.cc
|
materialx/nodes/mix_rgb.cc
|
||||||
|
materialx/nodes/mix_shader.cc
|
||||||
materialx/nodes/node_item.cc
|
materialx/nodes/node_item.cc
|
||||||
materialx/nodes/node_parser.cc
|
materialx/nodes/node_parser.cc
|
||||||
materialx/nodes/normal_map.cc
|
materialx/nodes/normal_map.cc
|
||||||
materialx/nodes/output_material.cc
|
materialx/nodes/output_material.cc
|
||||||
materialx/nodes/sepcomb_color.cc
|
materialx/nodes/sepcomb_color.cc
|
||||||
materialx/nodes/sepcomb_xyz.cc
|
materialx/nodes/sepcomb_xyz.cc
|
||||||
|
materialx/nodes/subsurface_scattering.cc
|
||||||
materialx/nodes/tex_checker.cc
|
materialx/nodes/tex_checker.cc
|
||||||
materialx/nodes/tex_environment.cc
|
materialx/nodes/tex_environment.cc
|
||||||
materialx/nodes/tex_image.cc
|
materialx/nodes/tex_image.cc
|
||||||
|
@ -17,9 +17,7 @@ namespace blender::nodes::materialx {
|
|||||||
|
|
||||||
CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader");
|
CLG_LOGREF_DECLARE_GLOBAL(LOG_MATERIALX_SHADER, "materialx.shader");
|
||||||
|
|
||||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material)
|
||||||
Material *material,
|
|
||||||
const std::string &socket_name)
|
|
||||||
{
|
{
|
||||||
CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name);
|
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) {
|
if (material->use_nodes) {
|
||||||
material->nodetree->ensure_topology_cache();
|
material->nodetree->ensure_topology_cache();
|
||||||
bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL);
|
bNode *output_node = ntreeShaderOutputNode(material->nodetree, SHD_OUTPUT_ALL);
|
||||||
OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute(socket_name);
|
OutputMaterialNodeParser(doc.get(), depsgraph, material, output_node).compute_full();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default();
|
OutputMaterialNodeParser(doc.get(), depsgraph, material, nullptr).compute_default();
|
||||||
|
@ -15,8 +15,6 @@ namespace blender::nodes::materialx {
|
|||||||
|
|
||||||
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
|
extern struct CLG_LogRef *LOG_MATERIALX_SHADER;
|
||||||
|
|
||||||
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
|
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material);
|
||||||
Material *material,
|
|
||||||
const std::string &socket_name = "Surface");
|
|
||||||
|
|
||||||
} // namespace blender::nodes::materialx
|
} // 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()
|
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 base_color = get_input_value("Base Color", NodeItem::Type::Color3);
|
||||||
|
|
||||||
NodeItem subsurface = get_input_value("Subsurface", NodeItem::Type::Float);
|
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);
|
NodeItem alpha = get_input_value("Alpha", NodeItem::Type::Float);
|
||||||
// transparency = 1.0 - alpha
|
// transparency = 1.0 - alpha
|
||||||
|
|
||||||
NodeItem normal = get_input_link("Normal");
|
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
|
||||||
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal");
|
NodeItem clearcoat_normal = get_input_link("Clearcoat Normal", NodeItem::Type::Vector3);
|
||||||
NodeItem tangent = get_input_link("Tangent");
|
NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3);
|
||||||
|
|
||||||
/* Creating standard_surface */
|
/* Creating standard_surface */
|
||||||
NodeItem res = create_node("standard_surface", "surfaceshader");
|
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();
|
NodeItem res = empty();
|
||||||
|
|
||||||
/* Single operand operations */
|
/* Single operand operations */
|
||||||
NodeItem x = get_input_value(0, NodeItem::Type::Empty);
|
NodeItem x = get_input_value(0, NodeItem::Type::Any);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case NODE_MATH_SINE:
|
case NODE_MATH_SINE:
|
||||||
res = x.sin();
|
res = x.sin();
|
||||||
@ -82,7 +82,7 @@ NodeItem MathNodeParser::compute()
|
|||||||
|
|
||||||
default: {
|
default: {
|
||||||
/* 2-operand operations */
|
/* 2-operand operations */
|
||||||
NodeItem y = get_input_value(1, NodeItem::Type::Empty);
|
NodeItem y = get_input_value(1, NodeItem::Type::Any);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case NODE_MATH_ADD:
|
case NODE_MATH_ADD:
|
||||||
res = x + y;
|
res = x + y;
|
||||||
@ -132,7 +132,7 @@ NodeItem MathNodeParser::compute()
|
|||||||
|
|
||||||
default: {
|
default: {
|
||||||
/* 3-operand operations */
|
/* 3-operand operations */
|
||||||
NodeItem z = get_input_value(2, NodeItem::Type::Empty);
|
NodeItem z = get_input_value(2, NodeItem::Type::Any);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case NODE_MATH_WRAP:
|
case NODE_MATH_WRAP:
|
||||||
CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op);
|
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::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
|
NodeItem::operator bool() const
|
||||||
{
|
{
|
||||||
return value || node;
|
return value || node;
|
||||||
@ -19,6 +99,21 @@ NodeItem::operator bool() const
|
|||||||
|
|
||||||
NodeItem NodeItem::operator+(const NodeItem &other) 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; });
|
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
|
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; });
|
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 item1 = *this;
|
||||||
NodeItem item2 = other;
|
NodeItem item2 = other;
|
||||||
Type to_type = adjust_types(item1, item2);
|
Type to_type = cast_types(item1, item2);
|
||||||
if (to_type == Type::Empty) {
|
if (to_type == Type::Empty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -248,10 +359,14 @@ NodeItem NodeItem::extract(const int index) const
|
|||||||
NodeItem NodeItem::convert(Type to_type) const
|
NodeItem NodeItem::convert(Type to_type) const
|
||||||
{
|
{
|
||||||
Type from_type = type();
|
Type from_type = type();
|
||||||
if (from_type == to_type) {
|
if (from_type == Type::Empty || from_type == to_type || to_type == Type::Any) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) {
|
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();
|
return empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,7 +563,7 @@ NodeItem NodeItem::if_else(CompareOp op,
|
|||||||
|
|
||||||
auto item1 = if_val;
|
auto item1 = if_val;
|
||||||
auto item2 = else_val;
|
auto item2 = else_val;
|
||||||
Type to_type = adjust_types(item1, item2);
|
Type to_type = cast_types(item1, item2);
|
||||||
if (to_type == Type::Empty) {
|
if (to_type == Type::Empty) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -554,66 +669,12 @@ void NodeItem::add_output(const std::string &name, Type out_type)
|
|||||||
node->addOutput(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)
|
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 t1 = item1.type();
|
||||||
Type t2 = item2.type();
|
Type t2 = item2.type();
|
||||||
@ -621,6 +682,8 @@ NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
|
|||||||
return t1;
|
return t1;
|
||||||
}
|
}
|
||||||
if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
|
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;
|
return Type::Empty;
|
||||||
}
|
}
|
||||||
if (t1 < t2) {
|
if (t1 < t2) {
|
||||||
@ -701,7 +764,7 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
|
|||||||
NodeItem res = empty();
|
NodeItem res = empty();
|
||||||
NodeItem item1 = *this;
|
NodeItem item1 = *this;
|
||||||
NodeItem item2 = other;
|
NodeItem item2 = other;
|
||||||
Type to_type = adjust_types(item1, item2);
|
Type to_type = cast_types(item1, item2);
|
||||||
if (to_type == Type::Empty) {
|
if (to_type == Type::Empty) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,28 @@ namespace blender::nodes::materialx {
|
|||||||
class NodeItem {
|
class NodeItem {
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Empty = 0,
|
Any = 0,
|
||||||
Other, /* For MaterialX types like: surfaceshader, bsdf, edf, ...*/
|
Empty,
|
||||||
|
|
||||||
|
/* Value types */
|
||||||
String,
|
String,
|
||||||
|
Filename,
|
||||||
Integer,
|
Integer,
|
||||||
|
/* Block of arithmetic types. Ordered by type cast */
|
||||||
Float,
|
Float,
|
||||||
Vector2,
|
Vector2,
|
||||||
Vector3,
|
Vector3,
|
||||||
Vector4,
|
|
||||||
Color3,
|
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 };
|
enum class CompareOp { Less = 0, LessEq, Eq, GreaterEq, Greater, NotEq };
|
||||||
|
|
||||||
@ -35,6 +47,9 @@ class NodeItem {
|
|||||||
NodeItem(MaterialX::GraphElement *graph);
|
NodeItem(MaterialX::GraphElement *graph);
|
||||||
~NodeItem() = default;
|
~NodeItem() = default;
|
||||||
|
|
||||||
|
static Type type(const std::string &type_str);
|
||||||
|
static std::string type(Type type);
|
||||||
|
|
||||||
/* Operators */
|
/* Operators */
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
NodeItem operator+(const NodeItem &other) const;
|
NodeItem operator+(const NodeItem &other) const;
|
||||||
@ -92,10 +107,8 @@ class NodeItem {
|
|||||||
void add_output(const std::string &in_name, Type out_type);
|
void add_output(const std::string &in_name, Type out_type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Type type(const std::string &type_str);
|
|
||||||
static std::string type(Type type);
|
|
||||||
static bool is_arithmetic(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;
|
bool is_arithmetic() const;
|
||||||
NodeItem arithmetic(const std::string &category, std::function<float(float)> func) 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 ?
|
CLOG_INFO(LOG_MATERIALX_SHADER, 1, "%s [%d]", node_->name, node_->typeinfo->type);
|
||||||
std::string(node->name) :
|
NodeItem res = compute();
|
||||||
std::string(node->name) + "_" + socket_out->name);
|
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)
|
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;
|
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
|
NodeItem NodeParser::empty() const
|
||||||
@ -71,7 +81,7 @@ NodeItem NodeParser::empty() const
|
|||||||
return NodeItem(graph_);
|
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();
|
NodeItem res = empty();
|
||||||
switch (socket.type) {
|
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);
|
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();
|
NodeItem res = empty();
|
||||||
|
|
||||||
@ -119,21 +129,16 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket)
|
|||||||
from_node = link->fromnode;
|
from_node = link->fromnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checking if node was already computed */
|
/* Creating required NodeParser object */
|
||||||
res.node = graph_->getNode(node_name(from_node, link->fromsock));
|
std::unique_ptr<NodeParser> parser;
|
||||||
if (res.node) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Computing from_node with required NodeParser object */
|
|
||||||
#define CASE_NODE_TYPE(type, T) \
|
#define CASE_NODE_TYPE(type, T) \
|
||||||
case type: \
|
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;
|
break;
|
||||||
|
|
||||||
switch (from_node->typeinfo->type) {
|
switch (from_node->typeinfo->type) {
|
||||||
CASE_NODE_TYPE(SH_NODE_BRIGHTCONTRAST, BrightContrastNodeParser)
|
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_COMBINE_COLOR, CombineColorNodeParser)
|
||||||
CASE_NODE_TYPE(SH_NODE_COMBXYZ, CombineXYZNodeParser)
|
CASE_NODE_TYPE(SH_NODE_COMBXYZ, CombineXYZNodeParser)
|
||||||
CASE_NODE_TYPE(SH_NODE_HUE_SAT, HueSatValNodeParser)
|
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->name,
|
||||||
from_node->typeinfo->type);
|
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;
|
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();
|
NodeItem res = compute();
|
||||||
if (res.node) {
|
if (res.node) {
|
||||||
res.node->setName(node_name(node_, socket_out_));
|
res.node->setName(node_name());
|
||||||
}
|
}
|
||||||
return res;
|
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
|
} // namespace blender::nodes::materialx
|
||||||
|
@ -31,24 +31,44 @@ class NodeParser {
|
|||||||
virtual NodeItem compute() = 0;
|
virtual NodeItem compute() = 0;
|
||||||
|
|
||||||
protected:
|
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 create_node(const std::string &mx_category, const std::string &mx_type);
|
||||||
NodeItem get_input_default(const std::string &name);
|
NodeItem get_input_default(const std::string &name, NodeItem::Type to_type);
|
||||||
NodeItem get_input_default(int index);
|
NodeItem get_input_default(int index, NodeItem::Type to_type);
|
||||||
NodeItem get_input_link(const std::string &name);
|
NodeItem get_input_link(const std::string &name, NodeItem::Type to_type);
|
||||||
NodeItem get_input_link(int index);
|
NodeItem get_input_link(int index, NodeItem::Type to_type);
|
||||||
NodeItem get_input_value(const std::string &name,
|
NodeItem get_input_value(const std::string &name, NodeItem::Type to_type);
|
||||||
const NodeItem::Type type);
|
NodeItem get_input_value(int index, NodeItem::Type to_type);
|
||||||
NodeItem get_input_value(int index, const NodeItem::Type type);
|
|
||||||
NodeItem empty() const;
|
NodeItem empty() const;
|
||||||
template<class T> NodeItem value(const T &data) const;
|
template<class T> NodeItem value(const T &data) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeItem get_input_default(const bNodeSocket &socket);
|
NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type);
|
||||||
NodeItem get_input_link(const bNodeSocket &socket);
|
NodeItem get_input_link(const bNodeSocket &socket, NodeItem::Type to_type);
|
||||||
NodeItem get_input_value(const bNodeSocket &socket,
|
NodeItem get_input_value(const bNodeSocket &socket, NodeItem::Type to_type);
|
||||||
const NodeItem::Type type);
|
};
|
||||||
NodeItem compute_full();
|
|
||||||
|
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
|
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);
|
return empty().val(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_PARSER(T) \
|
#define DECLARE_NODE_PARSER(T) \
|
||||||
class T : public NodeParser { \
|
class T : public NodeParser { \
|
||||||
public: \
|
public: \
|
||||||
using NodeParser::NodeParser; \
|
using NodeParser::NodeParser; \
|
||||||
NodeItem compute() override; \
|
NodeItem compute() override; \
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_PARSER(BrightContrastNodeParser)
|
#define DECLARE_SHADER_NODE_PARSER(T) \
|
||||||
DECLARE_PARSER(BSDFPrincipledNodeParser)
|
class T : public ShaderNodeParser { \
|
||||||
DECLARE_PARSER(CombineColorNodeParser)
|
public: \
|
||||||
DECLARE_PARSER(CombineXYZNodeParser)
|
using ShaderNodeParser::ShaderNodeParser; \
|
||||||
DECLARE_PARSER(HueSatValNodeParser)
|
NodeItem compute() override; \
|
||||||
DECLARE_PARSER(InvertNodeParser)
|
};
|
||||||
DECLARE_PARSER(MathNodeParser)
|
|
||||||
DECLARE_PARSER(MixRGBNodeParser)
|
DECLARE_NODE_PARSER(BrightContrastNodeParser)
|
||||||
DECLARE_PARSER(NormalMapNodeParser)
|
DECLARE_NODE_PARSER(CombineColorNodeParser)
|
||||||
DECLARE_PARSER(SeparateColorNodeParser)
|
DECLARE_NODE_PARSER(CombineXYZNodeParser)
|
||||||
DECLARE_PARSER(SeparateXYZNodeParser)
|
DECLARE_NODE_PARSER(HueSatValNodeParser)
|
||||||
DECLARE_PARSER(TexCheckerNodeParser)
|
DECLARE_NODE_PARSER(InvertNodeParser)
|
||||||
DECLARE_PARSER(TexEnvironmentNodeParser)
|
DECLARE_NODE_PARSER(MathNodeParser)
|
||||||
DECLARE_PARSER(TexImageNodeParser)
|
DECLARE_NODE_PARSER(MixRGBNodeParser)
|
||||||
DECLARE_PARSER(TexNoiseNodeParser)
|
DECLARE_NODE_PARSER(NormalMapNodeParser)
|
||||||
DECLARE_PARSER(VectorMathNodeParser)
|
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
|
} // namespace blender::nodes::materialx
|
||||||
|
@ -9,27 +9,34 @@ OutputMaterialNodeParser::OutputMaterialNodeParser(MaterialX::GraphElement *grap
|
|||||||
const Depsgraph *depsgraph,
|
const Depsgraph *depsgraph,
|
||||||
const Material *material,
|
const Material *material,
|
||||||
const bNode *node)
|
const bNode *node)
|
||||||
: NodeParser(graph, depsgraph, material, node, nullptr)
|
: ShaderNodeParser(graph, depsgraph, material, node, nullptr, NodeItem::Type::Material)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeItem OutputMaterialNodeParser::compute()
|
NodeItem OutputMaterialNodeParser::compute()
|
||||||
{
|
|
||||||
return empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeItem OutputMaterialNodeParser::compute(const std::string &socket_name)
|
|
||||||
{
|
{
|
||||||
NodeItem surface = empty();
|
NodeItem surface = empty();
|
||||||
if (node_) {
|
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 {
|
else {
|
||||||
surface = create_node("standard_surface", "surfaceshader");
|
surface = create_node("standard_surface", "surfaceshader");
|
||||||
surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
|
surface.set_input("base_color", value(MaterialX::Color3(1.0f, 0.0f, 1.0f)));
|
||||||
}
|
}
|
||||||
NodeItem res = create_node("surfacematerial", "material");
|
NodeItem res = create_node("surfacematerial", "material");
|
||||||
res.node->setName(node_name(node_, nullptr));
|
|
||||||
res.set_input("surfaceshader", surface);
|
res.set_input("surfaceshader", surface);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -55,4 +62,9 @@ NodeItem OutputMaterialNodeParser::compute_default()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string OutputMaterialNodeParser::node_name()
|
||||||
|
{
|
||||||
|
return NodeParser::node_name();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::nodes::materialx
|
} // namespace blender::nodes::materialx
|
||||||
|
@ -8,15 +8,19 @@
|
|||||||
|
|
||||||
namespace blender::nodes::materialx {
|
namespace blender::nodes::materialx {
|
||||||
|
|
||||||
class OutputMaterialNodeParser : public NodeParser {
|
class OutputMaterialNodeParser : public ShaderNodeParser {
|
||||||
public:
|
public:
|
||||||
OutputMaterialNodeParser(MaterialX::GraphElement *graph,
|
OutputMaterialNodeParser(MaterialX::GraphElement *graph,
|
||||||
const Depsgraph *depsgraph,
|
const Depsgraph *depsgraph,
|
||||||
const Material *material,
|
const Material *material,
|
||||||
const bNode *node);
|
const bNode *node);
|
||||||
NodeItem compute() override;
|
NodeItem compute() override;
|
||||||
NodeItem compute(const std::string &socket_name);
|
|
||||||
|
using ShaderNodeParser::compute_full;
|
||||||
NodeItem compute_default();
|
NodeItem compute_default();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string node_name() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::nodes::materialx
|
} // 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 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 color1 = get_input_value("Color1", NodeItem::Type::Color3);
|
||||||
NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3);
|
NodeItem color2 = get_input_value("Color2", NodeItem::Type::Color3);
|
||||||
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
|
||||||
@ -16,28 +16,13 @@ NodeItem TexCheckerNodeParser::compute()
|
|||||||
if (!vector) {
|
if (!vector) {
|
||||||
vector = create_node("texcoord", "vector2");
|
vector = create_node("texcoord", "vector2");
|
||||||
}
|
}
|
||||||
vector = vector * scale;
|
vector = (vector * scale) % value(2.0f);
|
||||||
|
NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor())
|
||||||
NodeItem separate = create_node("separate2", "multioutput");
|
.if_else(NodeItem::CompareOp::Eq, value(1.0f), value(1.0f), value(0.0f));
|
||||||
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));
|
|
||||||
|
|
||||||
NodeItem res = create_node("mix", "color3");
|
NodeItem res = create_node("mix", "color3");
|
||||||
res.set_input("bg", color1);
|
res.set_input("fg", color1);
|
||||||
res.set_input("fg", color2);
|
res.set_input("bg", color2);
|
||||||
res.set_input("mix", ifequal);
|
res.set_input("mix", mix);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ NodeItem VectorMathNodeParser::compute()
|
|||||||
NodeItem res = empty();
|
NodeItem res = empty();
|
||||||
|
|
||||||
/* Single operand operations */
|
/* Single operand operations */
|
||||||
NodeItem x = get_input_value(0, NodeItem::Type::Empty);
|
NodeItem x = get_input_value(0, NodeItem::Type::Any);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case NODE_VECTOR_MATH_SINE:
|
case NODE_VECTOR_MATH_SINE:
|
||||||
res = x.sin();
|
res = x.sin();
|
||||||
@ -46,7 +46,7 @@ NodeItem VectorMathNodeParser::compute()
|
|||||||
|
|
||||||
default: {
|
default: {
|
||||||
/* 2-operand operations */
|
/* 2-operand operations */
|
||||||
NodeItem y = get_input_value(1, NodeItem::Type::Empty);
|
NodeItem y = get_input_value(1, NodeItem::Type::Any);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case NODE_VECTOR_MATH_ADD:
|
case NODE_VECTOR_MATH_ADD:
|
||||||
res = x + y;
|
res = x + y;
|
||||||
@ -93,7 +93,7 @@ NodeItem VectorMathNodeParser::compute()
|
|||||||
|
|
||||||
default: {
|
default: {
|
||||||
/* 3-operand operations */
|
/* 3-operand operations */
|
||||||
NodeItem z = get_input_value(2, NodeItem::Type::Empty);
|
NodeItem z = get_input_value(2, NodeItem::Type::Any);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case NODE_VECTOR_MATH_MULTIPLY_ADD:
|
case NODE_VECTOR_MATH_MULTIPLY_ADD:
|
||||||
res = x * y + z;
|
res = x * y + z;
|
||||||
|
Loading…
Reference in New Issue
Block a user