diff --git a/source/blender/nodes/shader/materialx/nodes/math.cc b/source/blender/nodes/shader/materialx/nodes/math.cc index d7dd43cb0041..9af8f665769c 100644 --- a/source/blender/nodes/shader/materialx/nodes/math.cc +++ b/source/blender/nodes/shader/materialx/nodes/math.cc @@ -10,11 +10,13 @@ namespace blender::nodes::materialx { NodeItem MathNodeParser::compute() { /* TODO: finish some math operations */ - auto op = node_->custom1; + NodeMathOperation op = NodeMathOperation(node_->custom1); NodeItem res = empty(); /* Single operand operations */ - NodeItem x = get_input_value(0, NodeItem::Type::Any); + NodeItem x = get_input_value(0, NodeItem::Type::Float); + /* TODO: Seems we have to use average if Vector or Color are added */ + switch (op) { case NODE_MATH_SINE: res = x.sin(); @@ -82,7 +84,7 @@ NodeItem MathNodeParser::compute() default: { /* 2-operand operations */ - NodeItem y = get_input_value(1, NodeItem::Type::Any); + NodeItem y = get_input_value(1, NodeItem::Type::Float); switch (op) { case NODE_MATH_ADD: res = x + y; @@ -132,7 +134,7 @@ NodeItem MathNodeParser::compute() default: { /* 3-operand operations */ - NodeItem z = get_input_value(2, NodeItem::Type::Any); + NodeItem z = get_input_value(2, NodeItem::Type::Float); switch (op) { case NODE_MATH_WRAP: CLOG_WARN(LOG_MATERIALX_SHADER, "Unimplemented math operation %d", op); diff --git a/source/blender/nodes/shader/materialx/nodes/node_item.cc b/source/blender/nodes/shader/materialx/nodes/node_item.cc index efef38cec1ed..f7fea7c2c9a5 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_item.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_item.cc @@ -351,15 +351,6 @@ NodeItem NodeItem::exp() const return arithmetic("exp", [](float a) { return std::expf(a); }); } -NodeItem NodeItem::extract(const int index) const -{ - NodeItem res = empty(); - res = create_node("extract", Type::Float); - res.set_input("in", *this); - res.set_input("index", val(index)); - return res; -} - NodeItem NodeItem::convert(Type to_type) const { Type from_type = type(); @@ -605,6 +596,15 @@ NodeItem NodeItem::if_else(CompareOp op, return res; } +NodeItem NodeItem::extract(const int index) const +{ + NodeItem res = empty(); + res = create_node("extract", Type::Float); + res.set_input("in", *this); + res.set_input("index", val(index)); + return res; +} + NodeItem NodeItem::empty() const { return NodeItem(graph_); diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.cc b/source/blender/nodes/shader/materialx/nodes/node_parser.cc index ec017a5319a5..4433852a4e76 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.cc +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.cc @@ -9,6 +9,8 @@ namespace blender::nodes::materialx { +static const std::string TEXCOORD_NODE_NAME = "node_texcoord"; + NodeParser::NodeParser(MaterialX::GraphElement *graph, const Depsgraph *depsgraph, const Material *material, @@ -79,6 +81,17 @@ NodeItem NodeParser::empty() const return NodeItem(graph_); } +NodeItem NodeParser::texcoord_node() +{ + NodeItem res = empty(); + res.node = graph_->getNode(TEXCOORD_NODE_NAME); + if (!res.node) { + res = create_node("texcoord", NodeItem::Type::Vector2); + res.node->setName(TEXCOORD_NODE_NAME); + } + return res; +} + NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type) { NodeItem res = empty(); diff --git a/source/blender/nodes/shader/materialx/nodes/node_parser.h b/source/blender/nodes/shader/materialx/nodes/node_parser.h index 9cfc729439c3..d23471db8c05 100644 --- a/source/blender/nodes/shader/materialx/nodes/node_parser.h +++ b/source/blender/nodes/shader/materialx/nodes/node_parser.h @@ -42,6 +42,7 @@ class NodeParser { NodeItem get_input_value(int index, NodeItem::Type to_type); NodeItem empty() const; template NodeItem val(const T &data) const; + NodeItem texcoord_node(); private: NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type); diff --git a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc index 746cdab98031..1d58e0e14a82 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_checker.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_checker.cc @@ -9,21 +9,20 @@ namespace blender::nodes::materialx { NodeItem TexCheckerNodeParser::compute() { 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); + if (!vector) { + vector = texcoord_node(); + } + NodeItem value1 = val(1.0f); + NodeItem value2 = val(0.0f); + if (STREQ(socket_out_->name, "Color")) { + value1 = get_input_value("Color1", NodeItem::Type::Color4); + value2 = get_input_value("Color2", NodeItem::Type::Color4); + } NodeItem scale = get_input_value("Scale", NodeItem::Type::Float); - if (!vector) { - vector = create_node("texcoord", NodeItem::Type::Vector2); - } vector = (vector * scale) % val(2.0f); - NodeItem mix = (vector.extract(0).floor() + vector.extract(1).floor()) - .if_else(NodeItem::CompareOp::Eq, val(1.0f), val(1.0f), val(0.0f)); - NodeItem res = create_node("mix", NodeItem::Type::Color3); - res.set_input("fg", color1); - res.set_input("bg", color2); - res.set_input("mix", mix); - return res; + return (vector.extract(0).floor() + vector.extract(1).floor()) + .if_else(NodeItem::CompareOp::Eq, val(1.0f), value1, value2); } } // namespace blender::nodes::materialx diff --git a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc index 97e5a61bbeb7..65b5c451559b 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_environment.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_environment.cc @@ -12,21 +12,49 @@ namespace blender::nodes::materialx { NodeItem TexEnvironmentNodeParser::compute() { + NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); + Image *image = (Image *)node_->id; - NodeTexEnvironment *tex = static_cast(node_->storage); + if (!image) { + return res; + } + + NodeTexEnvironment *tex_env = static_cast(node_->storage); Scene *scene = DEG_get_input_scene(depsgraph_); Main *bmain = DEG_get_bmain(depsgraph_); - std::string image_path; + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains * pretty general code, so could be moved from bf_usd project. */ -#ifdef WITH_HYDRA - image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); -#endif + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_env->iuser); - NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2); - NodeItem res = create_node("image", NodeItem::Type::Color3); + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: texcoords should be translated to spherical coordinates */ + + std::string filtertype; + switch (tex_env->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", texcoord); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + return res; } diff --git a/source/blender/nodes/shader/materialx/nodes/tex_image.cc b/source/blender/nodes/shader/materialx/nodes/tex_image.cc index 9ad1163aed51..75c30a0a045f 100644 --- a/source/blender/nodes/shader/materialx/nodes/tex_image.cc +++ b/source/blender/nodes/shader/materialx/nodes/tex_image.cc @@ -12,21 +12,69 @@ namespace blender::nodes::materialx { NodeItem TexImageNodeParser::compute() { - Image *image = (Image *)node_->id; - NodeTexImage *tex = static_cast(node_->storage); - Scene *scene = DEG_get_input_scene(depsgraph_); - Main *bmain = DEG_get_bmain(depsgraph_); - std::string image_path; - /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains - * pretty general code, so could be moved from bf_usd project. */ -#ifdef WITH_HYDRA - image_path = io::hydra::cache_or_get_image_file(bmain, scene, image, &tex->iuser); -#endif + NodeItem res = val(MaterialX::Color4(1.0f, 0.0f, 1.0f, 1.0f)); - NodeItem texcoord = create_node("texcoord", NodeItem::Type::Vector2); - NodeItem res = create_node("image", NodeItem::Type::Color3); - res.set_input("file", image_path, NodeItem::Type::Filename); - res.set_input("texcoord", texcoord); + Image *image = (Image *)node_->id; + if (image) { + NodeTexImage *tex_image = static_cast(node_->storage); + Scene *scene = DEG_get_input_scene(depsgraph_); + Main *bmain = DEG_get_bmain(depsgraph_); + + /* TODO: What if Blender built without Hydra? Also io::hydra::cache_or_get_image_file contains + * pretty general code, so could be moved from bf_usd project. */ + std::string image_path = io::hydra::cache_or_get_image_file( + bmain, scene, image, &tex_image->iuser); + + NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2); + if (!vector) { + vector = texcoord_node(); + } + /* TODO: add math to vector depending of tex_image->projection */ + + std::string filtertype; + switch (tex_image->interpolation) { + case SHD_INTERP_LINEAR: + filtertype = "linear"; + break; + case SHD_INTERP_CLOSEST: + filtertype = "closest"; + break; + case SHD_INTERP_CUBIC: + case SHD_INTERP_SMART: + filtertype = "cubic"; + break; + default: + BLI_assert_unreachable(); + } + std::string addressmode; + switch (tex_image->extension) { + case SHD_IMAGE_EXTENSION_REPEAT: + addressmode = "periodic"; + break; + case SHD_IMAGE_EXTENSION_EXTEND: + addressmode = "clamp"; + break; + case SHD_IMAGE_EXTENSION_CLIP: + addressmode = "constant"; + break; + case SHD_IMAGE_EXTENSION_MIRROR: + addressmode = "mirror"; + break; + default: + BLI_assert_unreachable(); + } + + res = create_node("image", NodeItem::Type::Color4); + res.set_input("file", image_path, NodeItem::Type::Filename); + res.set_input("texcoord", vector); + res.set_input("filtertype", val(filtertype)); + res.set_input("uaddressmode", val(addressmode)); + res.set_input("vaddressmode", val(addressmode)); + } + + if (STREQ(socket_out_->name, "Alpha")) { + res = res.extract(3); + } return res; }