MaterialX: Implement export of Input nodes #20

Merged
Bogdan Nagirniak merged 26 commits from Vasyl-Pidhirskyi/blender:BLEN-530 into matx-export-material 2023-09-15 19:55:37 +02:00
20 changed files with 279 additions and 18 deletions

View File

@ -33,20 +33,18 @@ NodeItem NodeParser::compute_full()
/* Checking if node was already computed */
res.node = graph_->getNode(node_name());
if (res.node) {
return res;
}
if (!res.node) {
CLOG_INFO(LOG_MATERIALX_SHADER,
1,
"%s [%d] => %s",
node_->name,
node_->typeinfo->type,
NodeItem::type(to_type_).c_str());
CLOG_INFO(LOG_MATERIALX_SHADER,
1,
"%s [%d] => %s",
node_->name,
node_->typeinfo->type,
NodeItem::type(to_type_).c_str());
res = compute();
if (res.node) {
res.node->setName(node_name());
res = compute();
if (res.node) {
res.node->setName(node_name());
}
}
if (NodeItem::is_arithmetic(to_type_)) {
res = res.convert(to_type_);
@ -73,12 +71,12 @@ NodeItem NodeParser::create_node(const std::string &category, NodeItem::Type typ
NodeItem NodeParser::get_input_default(const std::string &name, NodeItem::Type to_type)
{
return get_input_default(node_->input_by_identifier(name), to_type);
return get_default(node_->input_by_identifier(name), to_type);
}
NodeItem NodeParser::get_input_default(int index, NodeItem::Type to_type)
{
return get_input_default(node_->input_socket(index), to_type);
return get_default(node_->input_socket(index), to_type);
}
NodeItem NodeParser::get_input_link(const std::string &name, NodeItem::Type to_type)
@ -101,6 +99,16 @@ NodeItem NodeParser::get_input_value(int index, NodeItem::Type to_type)
return get_input_value(node_->input_socket(index), to_type);
}
NodeItem NodeParser::get_output_default(const std::string &name, NodeItem::Type to_type)
{
return get_default(node_->output_by_identifier(name), to_type);
}
NodeItem NodeParser::get_output_default(int index, NodeItem::Type to_type)
{
return get_default(node_->output_socket(index), to_type);
}
NodeItem NodeParser::empty() const
{
return NodeItem(graph_);
@ -117,7 +125,7 @@ NodeItem NodeParser::texcoord_node()
return res;
}
NodeItem NodeParser::get_input_default(const bNodeSocket &socket, NodeItem::Type to_type)
NodeItem NodeParser::get_default(const bNodeSocket &socket, NodeItem::Type to_type)
{
NodeItem res = empty();
switch (socket.type) {
@ -180,7 +188,7 @@ NodeItem NodeParser::get_input_value(const bNodeSocket &socket, NodeItem::Type t
{
NodeItem res = get_input_link(socket, to_type);
if (!res) {
res = get_input_default(socket, to_type);
res = get_default(socket, to_type);
}
return res;
}

View File

@ -42,6 +42,8 @@ class NodeParser {
NodeItem create_node(const std::string &category, NodeItem::Type type);
NodeItem get_input_default(const std::string &name, NodeItem::Type to_type);
NodeItem get_input_default(int index, NodeItem::Type to_type);
NodeItem get_output_default(const std::string &name, NodeItem::Type to_type);
NodeItem get_output_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);
@ -51,7 +53,7 @@ class NodeParser {
NodeItem texcoord_node();
private:
NodeItem get_input_default(const bNodeSocket &socket, NodeItem::Type to_type);
NodeItem get_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);
BogdanNagirniak marked this conversation as resolved Outdated

use one function here instead of 3 get_default(const bNodeSocket &socket, NodeItem::Type to_type)

use one function here instead of 3 `get_default(const bNodeSocket &socket, NodeItem::Type to_type)`
};

View File

@ -55,6 +55,21 @@ static void node_shader_init_ambient_occlusion(bNodeTree * /*ntree*/, bNode *nod
node->custom2 = 0;
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* TODO: observed crash while rendering MaterialX_v1_38_6::ExceptionShaderGenError */
/*
* NodeItem maxdistance = get_input_value("Distance", NodeItem::Type::Float);
* NodeItem res = create_node("ambientocclusion", NodeItem::Type::Float);
* res.set_input("coneangle", val(90.0f));
* res.set_input("maxdistance", maxdistance);
*/
BogdanNagirniak marked this conversation as resolved
Review
NodeItem color = get_input_value("Color", NodeItem::Type::Color4);
NodeItem res = color;
``` NodeItem color = get_input_value("Color", NodeItem::Type::Color4); NodeItem res = color; ```
return get_output_default(socket_out_->name, NodeItem::Type::Any);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_ambient_occlusion_cc
/* node type definition */
@ -69,6 +84,7 @@ void register_node_type_sh_ambient_occlusion()
ntype.draw_buttons = file_ns::node_shader_buts_ambient_occlusion;
ntype.initfunc = file_ns::node_shader_init_ambient_occlusion;
ntype.gpu_fn = file_ns::node_shader_gpu_ambient_occlusion;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -77,6 +77,16 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
return 1;
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* TODO: some outputs expected be implemented within the next iteration (see nodedef
* <geompropvalue>) */
BogdanNagirniak marked this conversation as resolved
Review

Start with NodeItem res = empty(); add check if (STREQ(socket_out_->name, "Color"))

Start with `NodeItem res = empty();` add check `if (STREQ(socket_out_->name, "Color"))`
return get_output_default(socket_out_->name, NodeItem::Type::Any);
}
#endif
NODE_SHADER_MATERIALX_END
BogdanNagirniak marked this conversation as resolved Outdated

else if

`else if`
} // namespace blender::nodes::node_shader_attribute_cc
/* node type definition */
@ -93,6 +103,7 @@ void register_node_type_sh_attribute()
node_type_storage(
&ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::node_shader_gpu_attribute;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -39,6 +39,15 @@ static int gpu_shader_bevel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bevel", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
BogdanNagirniak marked this conversation as resolved
Review

NOTE instead TODO if there is no implementation in MatX. No need 1.38.6, just in MaterialX

`NOTE` instead `TODO` if there is no implementation in MatX. No need 1.38.6, just `in MaterialX`
/* NOTE: This node doesn't have an implementation in MaterialX.*/
BogdanNagirniak marked this conversation as resolved Outdated

return get_input_link("Normal", NodeItem::Type::Vector3);

`return get_input_link("Normal", NodeItem::Type::Vector3);`
return get_input_link("Normal", NodeItem::Type::Vector3);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_bevel_cc
/* node type definition */
@ -53,6 +62,7 @@ void register_node_type_sh_bevel()
ntype.draw_buttons = file_ns::node_shader_buts_bevel;
ntype.initfunc = file_ns::node_shader_init_bevel;
ntype.gpu_fn = file_ns::gpu_shader_bevel;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -26,6 +26,15 @@ static int gpu_shader_camera(GPUMaterial *mat,
return GPU_stack_link(mat, node, "camera", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: This node doesn't have an implementation in MaterialX.*/
return get_output_default(socket_out_->name, NodeItem::Type::Any);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_camera_cc
BogdanNagirniak marked this conversation as resolved Outdated

start from empty(), use else if

start from `empty()`, use `else if`
void register_node_type_sh_camera()
@ -37,6 +46,7 @@ void register_node_type_sh_camera()
sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::gpu_shader_camera;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -26,6 +26,16 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_fresnel", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* TODO: some outputs expected be implemented within the next iteration (see nodedef
* <artistic_ior>) */
return get_input_value("IOR", NodeItem::Type::Float);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_fresnel_cc
/* node type definition */
@ -38,6 +48,7 @@ void register_node_type_sh_fresnel()
sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_fresnel;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -58,6 +58,33 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
return success;
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: Some outputs don't have an implementation in MaterialX.*/
NodeItem res = empty();
std::string name = socket_out_->name;
BogdanNagirniak marked this conversation as resolved
Review

maybe std::string name = socket_out_->name ?

maybe std::string name = socket_out_->name ?
if (name == "Position") {
res = create_node("position", NodeItem::Type::Vector3);
res.set_input("space", val(std::string("world")));
}
else if (name == "Normal") {
res = create_node("normal", NodeItem::Type::Vector3);
res.set_input("space", val(std::string("world")));
}
else if (ELEM(name, "Tangent", "True Normal")) {
res = create_node("tangent", NodeItem::Type::Vector3);
res.set_input("space", val(std::string("world")));
}
else {
res = get_output_default(name, NodeItem::Type::Any);
}
return res;
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_geometry_cc
/* node type definition */
@ -70,6 +97,7 @@ void register_node_type_sh_geometry()
sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_geometry;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -29,6 +29,15 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: This node doesn't have an implementation in MaterialX.*/
return get_output_default(socket_out_->name, NodeItem::Type::Any);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_hair_info_cc
/* node type definition */
@ -41,6 +50,7 @@ void register_node_type_sh_hair_info()
sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Curves Info", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_hair_info;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -27,6 +27,16 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_layer_weight", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* TODO: some outputs expected be implemented partially within the next iteration (see nodedef
* <artistic_ior>) */
return get_input_link("Blend", NodeItem::Type::Float);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_layer_weight_cc
/* node type definition */
@ -39,6 +49,7 @@ void register_node_type_sh_layer_weight()
sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_layer_weight;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -30,6 +30,34 @@ static int node_shader_gpu_object_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_constant(&index));
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: Some outputs don't have an implementation in MaterialX.*/
NodeItem res = empty();
std::string name = socket_out_->name;
if (name == "Location") {
res = create_node("position", NodeItem::Type::Vector3);
res.set_input("space", val(std::string("world")));
}
/* TODO: This node doesn't have an implementation in MaterialX.
* It's added in MaterialX 1.38.8. Uncomment this code after switching to 1.38.8.
* if (name=="Random") {
* res = create_node("randomfloat", NodeItem::Type::Float);
* res.set_input("in", val(0.0));
* res.set_input("min", val(0.0));
* res.set_input("max", val(1.0));
* res.set_input("seed", val(0));
*}*/
else {
res = get_output_default(name, NodeItem::Type::Any);
}
return res;
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_object_info_cc
void register_node_type_sh_object_info()
@ -41,6 +69,7 @@ void register_node_type_sh_object_info()
sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_object_info;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -34,6 +34,15 @@ static int gpu_shader_particle_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "particle_info", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: This node doesn't have an implementation in MaterialX.*/
return get_output_default(socket_out_->name, NodeItem::Type::Any);
BogdanNagirniak marked this conversation as resolved Outdated

use std::string name = socket_out_->name and ELEM(name, ....)

use `std::string name = socket_out_->name` and `ELEM(name, ....)`
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_particle_info_cc
/* node type definition */
@ -46,6 +55,7 @@ void register_node_type_sh_particle_info()
sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::gpu_shader_particle_info;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -22,6 +22,15 @@ static int node_shader_gpu_point_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_point_info", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: This node doesn't have an implementation in MaterialX.*/
return get_output_default(socket_out_->name, NodeItem::Type::Any);
}
#endif
NODE_SHADER_MATERIALX_END
BogdanNagirniak marked this conversation as resolved
Review

I think return get_output_default can be used here

I think `return get_output_default` can be used here
} // namespace blender::nodes::node_shader_point_info_cc
/* node type definition */
@ -34,6 +43,7 @@ void register_node_type_sh_point_info()
sh_node_type_base(&ntype, SH_NODE_POINT_INFO, "Point Info", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_point_info;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -26,6 +26,17 @@ static int gpu_shader_rgb(GPUMaterial *mat,
return GPU_link(mat, "set_rgba", GPU_uniform(value), &out->link);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
NodeItem color = get_output_default("Color", NodeItem::Type::Color4);
NodeItem res = create_node("constant", NodeItem::Type::Color4);
res.set_input("value", color);
return res;
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_rgb_cc
void register_node_type_sh_rgb()
@ -37,6 +48,7 @@ void register_node_type_sh_rgb()
sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::gpu_shader_rgb;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -86,6 +86,15 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tangent", in, out, orco);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* TODO: This node doesn't have an implementation in MaterialX.*/
return get_output_default(socket_out_->name, NodeItem::Type::Vector3);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_tangent_cc
/* node type definition */
@ -103,6 +112,7 @@ void register_node_type_sh_tangent()
ntype.gpu_fn = file_ns::node_shader_gpu_tangent;
node_type_storage(
&ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage);
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -71,6 +71,33 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
return 1;
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: Some outputs don't have an implementation in MaterialX.*/
BogdanNagirniak marked this conversation as resolved Outdated

This node I think has to be implemented in this PR

This node I think has to be implemented in this PR
NodeItem res = empty();
std::string name = socket_out_->name;
if (ELEM(name, "Generated", "UV")) {
res = texcoord_node();
}
else if (name == "Normal") {
res = create_node("normal", NodeItem::Type::Vector3);
res.set_input("space", val(std::string("world")));
}
else if (name == "Object") {
res = create_node("position", NodeItem::Type::Vector3);
res.set_input("space", val(std::string("world")));
}
else {
res = get_output_default(name, NodeItem::Type::Any);
}
return res;
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_tex_coord_cc
/* node type definition */
@ -84,6 +111,7 @@ void register_node_type_sh_tex_coord()
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_shader_buts_tex_coord;
ntype.gpu_fn = file_ns::node_shader_gpu_tex_coord;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -67,6 +67,17 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
return 1;
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
BogdanNagirniak marked this conversation as resolved
Review

I think it is implemented here, use NOTE that other properties of node are unsupported

I think it is implemented here, use NOTE that other properties of node are unsupported
/* NODE: "From Instances" not implemented
* UV selection not implemented
*/
return texcoord_node();
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_uvmap_cc
/* node type definition */
@ -84,6 +95,7 @@ void register_node_type_sh_uvmap()
node_type_storage(
&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::node_shader_gpu_uvmap;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -38,6 +38,17 @@ static void sh_node_value_build_multi_function(NodeMultiFunctionBuilder &builder
builder.construct_and_set_matching_fn<mf::CustomMF_Constant<float>>(value->value);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
NodeItem value = get_output_default("Value", NodeItem::Type::Float);
NodeItem res = create_node("constant", NodeItem::Type::Float);
res.set_input("value", value);
return res;
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_value_cc
void register_node_type_sh_value()
@ -50,6 +61,7 @@ void register_node_type_sh_value()
ntype.declare = file_ns::sh_node_value_declare;
ntype.gpu_fn = file_ns::gpu_shader_value;
ntype.build_multi_function = file_ns::sh_node_value_build_multi_function;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -67,6 +67,16 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* TODO: some output expected be implemented within the next iteration (see nodedef
* <geomcolor>)*/
BogdanNagirniak marked this conversation as resolved
Review

start from empty()

start from empty()
return get_output_default(socket_out_->name, NodeItem::Type::Any);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_vertex_color_cc
void register_node_type_sh_vertex_color()
@ -82,6 +92,7 @@ void register_node_type_sh_vertex_color()
node_type_storage(
&ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
ntype.gpu_fn = file_ns::node_shader_gpu_vertex_color;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

View File

@ -40,6 +40,15 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
}
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NOTE: This node doesn't have an implementation in MaterialX.*/
return get_output_default(socket_out_->name, NodeItem::Type::Float);
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_wireframe_cc
/* node type definition */
@ -53,6 +62,7 @@ void register_node_type_sh_wireframe()
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_shader_buts_wireframe;
ntype.gpu_fn = file_ns::node_shader_gpu_wireframe;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}