USD: Rename active UV Map to "st" by default

This was previously attempted in #109518 and reverted in #112234. Now do
both the changes in the mesh and material export, and make it an option
in USD export. Hydra always renamed to "st" and continues to do it.

Fix #122800: Missing textures with MaterialX materials

Pull Request: https://projects.blender.org/blender/blender/pulls/123326
This commit is contained in:
Brecht Van Lommel
2024-06-19 17:53:55 +02:00
committed by Brecht Van Lommel
parent dfd9f9066b
commit eaeb8ba8cd
16 changed files with 113 additions and 78 deletions

View File

@@ -216,6 +216,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
const bool export_animation = RNA_boolean_get(op->ptr, "export_animation");
const bool export_hair = RNA_boolean_get(op->ptr, "export_hair");
const bool export_uvmaps = RNA_boolean_get(op->ptr, "export_uvmaps");
const bool rename_uvmaps = RNA_boolean_get(op->ptr, "rename_uvmaps");
const bool export_mesh_colors = RNA_boolean_get(op->ptr, "export_mesh_colors");
const bool export_normals = RNA_boolean_get(op->ptr, "export_normals");
const bool export_materials = RNA_boolean_get(op->ptr, "export_materials");
@@ -276,6 +277,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
export_animation,
export_hair,
export_uvmaps,
rename_uvmaps,
export_normals,
export_mesh_colors,
export_materials,
@@ -376,6 +378,7 @@ static void wm_usd_export_draw(bContext *C, wmOperator *op)
{
uiLayout *col = uiLayoutColumn(panel, false);
uiItemR(col, ptr, "export_uvmaps", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "rename_uvmaps", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "export_normals", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "triangulate_meshes", UI_ITEM_NONE, nullptr, ICON_NONE);
@@ -540,6 +543,11 @@ void WM_OT_usd_export(wmOperatorType *ot)
ot->srna, "export_hair", false, "Hair", "Export hair particle systems as USD curves");
RNA_def_boolean(
ot->srna, "export_uvmaps", true, "UV Maps", "Include all mesh UV maps in the export");
RNA_def_boolean(ot->srna,
"rename_uvmaps",
true,
"Rename UV Maps",
"Rename active render UV map to \"st\" to match USD conventions");
RNA_def_boolean(ot->srna,
"export_mesh_colors",
true,

View File

@@ -86,9 +86,11 @@ void MaterialData::init()
pxr::UsdShadeMaterial usd_material;
#ifdef WITH_MATERIALX
if (scene_delegate_->use_materialx) {
blender::nodes::materialx::ExportParams materialx_export_params{
cache_or_get_image_file, "st", "UVMap"};
std::string material_name = pxr::TfMakeValidIdentifier(id->name);
MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx(
scene_delegate_->depsgraph, (Material *)id, material_name, cache_or_get_image_file);
scene_delegate_->depsgraph, (Material *)id, material_name, materialx_export_params);
pxr::UsdMtlxRead(doc, stage);
/* Logging stage: creating lambda stage_str() to not call stage->ExportToString()

View File

@@ -19,8 +19,6 @@ namespace blender::io::usd {
class USDHierarchyIterator;
using ExportImageFunction = std::function<std::string(Main *, Scene *, Image *, ImageUser *)>;
struct USDExporterContext {
Main *bmain;
Depsgraph *depsgraph;
@@ -35,7 +33,7 @@ struct USDExporterContext {
std::function<pxr::UsdTimeCode()> get_time_code;
const USDExportParams &export_params;
std::string export_file_path;
ExportImageFunction export_image_fn;
std::function<std::string(Main *, Scene *, Image *, ImageUser *)> export_image_fn;
};
} // namespace blender::io::usd

View File

@@ -95,11 +95,6 @@ static const pxr::TfToken translation("translation", pxr::TfToken::Immortal);
static const pxr::TfToken rotation("rotation", pxr::TfToken::Immortal);
} // namespace usdtokens
/* Cycles specific tokens. */
namespace cyclestokens {
static const std::string UVMap("UVMap");
} // namespace cyclestokens
namespace blender::io::usd {
/* Preview surface input specification. */
@@ -127,7 +122,7 @@ static void create_uv_input(const USDExporterContext &usd_export_context,
bNodeSocket *input_socket,
pxr::UsdShadeMaterial &usd_material,
pxr::UsdShadeInput &usd_input,
const std::string &default_uv,
const std::string &active_uvmap_name,
ReportList *reports);
static void export_texture(const USDExporterContext &usd_export_context, bNode *node);
static bNode *find_bsdf_node(Material *material);
@@ -156,16 +151,13 @@ void create_input(pxr::UsdShadeShader &shader,
static void create_usd_preview_surface_material(const USDExporterContext &usd_export_context,
Material *material,
pxr::UsdShadeMaterial &usd_material,
const std::string &default_uv,
const std::string &active_uvmap_name,
ReportList *reports)
{
if (!material) {
return;
}
/* Default map when creating UV primvar reader shaders. */
std::string default_uv_sampler = default_uv.empty() ? cyclestokens::UVMap : default_uv;
/* We only handle the first instance of either principled or
* diffuse bsdf nodes in the material's node tree, because
* USD Preview Surface has no concept of layering materials. */
@@ -303,7 +295,7 @@ static void create_usd_preview_surface_material(const USDExporterContext &usd_ex
pxr::SdfValueTypeNames->Float2))
{
create_uv_input(
usd_export_context, socket, usd_material, st_input, default_uv_sampler, reports);
usd_export_context, socket, usd_material, st_input, active_uvmap_name, reports);
}
}
@@ -460,7 +452,7 @@ static void create_uvmap_shader(const USDExporterContext &usd_export_context,
bNodeLink *uvmap_link,
pxr::UsdShadeMaterial &usd_material,
pxr::UsdShadeInput &usd_input,
const std::string &default_uv,
const std::string &active_uvmap_name,
ReportList *reports)
{
@@ -478,13 +470,16 @@ static void create_uvmap_shader(const USDExporterContext &usd_export_context,
return;
}
std::string uv_name = default_uv;
std::string uv_name = active_uvmap_name;
if (uv_node && uv_node->storage) {
NodeShaderUVMap *shader_uv_map = static_cast<NodeShaderUVMap *>(uv_node->storage);
/* We need to make valid here because actual uv primvar has been. */
uv_name = make_safe_name(shader_uv_map->uv_map,
usd_export_context.export_params.allow_unicode);
uv_name = shader_uv_map->uv_map;
}
if (usd_export_context.export_params.rename_uvmaps && uv_name == active_uvmap_name) {
uv_name = usdtokens::st;
}
/* We need to make valid, same as was done when exporting UV primvar. */
uv_name = make_safe_name(uv_name, usd_export_context.export_params.allow_unicode);
uv_shader.CreateInput(usdtokens::varname, pxr::SdfValueTypeNames->String).Set(uv_name);
usd_input.ConnectToSource(uv_shader.ConnectableAPI(), usdtokens::result);
@@ -494,7 +489,7 @@ static void create_transform2d_shader(const USDExporterContext &usd_export_conte
bNodeLink *mapping_link,
pxr::UsdShadeMaterial &usd_material,
pxr::UsdShadeInput &usd_input,
const std::string &default_uv,
const std::string &uvmap_name,
ReportList *reports)
{
@@ -509,7 +504,7 @@ static void create_transform2d_shader(const USDExporterContext &usd_export_conte
if (mapping_node->custom1 != TEXMAP_TYPE_POINT) {
if (bNodeSocket *socket = bke::nodeFindSocket(mapping_node, SOCK_IN, "Vector")) {
create_uv_input(usd_export_context, socket, usd_material, usd_input, default_uv, reports);
create_uv_input(usd_export_context, socket, usd_material, usd_input, uvmap_name, reports);
}
return;
}
@@ -573,7 +568,7 @@ static void create_transform2d_shader(const USDExporterContext &usd_export_conte
if (pxr::UsdShadeInput in_input = transform2d_shader.CreateInput(
usdtokens::in, pxr::SdfValueTypeNames->Float2))
{
create_uv_input(usd_export_context, socket, usd_material, in_input, default_uv, reports);
create_uv_input(usd_export_context, socket, usd_material, in_input, uvmap_name, reports);
}
}
}
@@ -582,7 +577,7 @@ static void create_uv_input(const USDExporterContext &usd_export_context,
bNodeSocket *input_socket,
pxr::UsdShadeMaterial &usd_material,
pxr::UsdShadeInput &usd_input,
const std::string &default_uv,
const std::string &active_uvmap_name,
ReportList *reports)
{
if (!(usd_material && usd_input)) {
@@ -590,8 +585,11 @@ static void create_uv_input(const USDExporterContext &usd_export_context,
}
if (bNodeLink *mapping_link = traverse_channel(input_socket, SH_NODE_MAPPING)) {
/* Use either "st" or active UV map name from mesh, depending if it was renamed. */
std::string uvmap_name = (usd_export_context.export_params.rename_uvmaps) ? usdtokens::st :
active_uvmap_name;
create_transform2d_shader(
usd_export_context, mapping_link, usd_material, usd_input, default_uv, reports);
usd_export_context, mapping_link, usd_material, usd_input, uvmap_name, reports);
return;
}
@@ -599,7 +597,7 @@ static void create_uv_input(const USDExporterContext &usd_export_context,
/* Note that uvmap_link might be null, but create_uv_shader() can handle this case. */
create_uvmap_shader(
usd_export_context, uvmap_link, usd_material, usd_input, default_uv, reports);
usd_export_context, uvmap_link, usd_material, usd_input, active_uvmap_name, reports);
}
/* Generate a file name for an in-memory image that doesn't have a
@@ -1168,22 +1166,27 @@ static pxr::SdfPath reflow_materialx_paths(pxr::SdfPath input_path,
static void create_usd_materialx_material(const USDExporterContext &usd_export_context,
pxr::SdfPath usd_path,
Material *material,
const std::string &active_uvmap_name,
pxr::UsdShadeMaterial &usd_material)
{
blender::nodes::materialx::ExportParams export_params = {
/* We want to re-use the same MaterialX document generation code as used by the renderer.
* While the graph is traversed, we also want it to export the textures out. */
(usd_export_context.export_image_fn) ? usd_export_context.export_image_fn :
std::bind(materialx_export_image,
usd_export_context,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4),
/* Active UV map name to use for default texture coordinates. */
(usd_export_context.export_params.rename_uvmaps) ? "st" : active_uvmap_name,
active_uvmap_name,
};
/* We want to re-use the same MaterialX document generation code as used by the renderer.
* While the graph is traversed, we also want it to export the textures out. */
ExportImageFunction export_image_fn = (usd_export_context.export_image_fn) ?
usd_export_context.export_image_fn :
std::bind(materialx_export_image,
usd_export_context,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4);
std::string material_name = usd_path.GetElementString();
MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx(
usd_export_context.depsgraph, material, material_name, export_image_fn);
usd_export_context.depsgraph, material, material_name, export_params);
/* We want to merge the MaterialX graph under the same Material as the USDPreviewSurface
* This allows for the same material assignment to have two levels of complexity so other
@@ -1352,7 +1355,7 @@ static void create_usd_materialx_material(const USDExporterContext &usd_export_c
pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_context,
pxr::SdfPath usd_path,
Material *material,
const std::string &active_uv,
const std::string &active_uvmap_name,
ReportList *reports)
{
pxr::UsdShadeMaterial usd_material = pxr::UsdShadeMaterial::Define(usd_export_context.stage,
@@ -1360,7 +1363,7 @@ pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_c
if (material->use_nodes && usd_export_context.export_params.generate_preview_surface) {
create_usd_preview_surface_material(
usd_export_context, material, usd_material, active_uv, reports);
usd_export_context, material, usd_material, active_uvmap_name, reports);
}
else {
create_usd_viewport_material(usd_export_context, material, usd_material);
@@ -1368,7 +1371,8 @@ pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_c
#ifdef WITH_MATERIALX
if (material->use_nodes && usd_export_context.export_params.generate_materialx_network) {
create_usd_materialx_material(usd_export_context, usd_path, material, usd_material);
create_usd_materialx_material(
usd_export_context, usd_path, material, active_uvmap_name, usd_material);
}
#endif

View File

@@ -24,7 +24,7 @@ struct USDExportParams;
pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_context,
pxr::SdfPath usd_path,
Material *material,
const std::string &active_uv,
const std::string &active_uvmap_name,
ReportList *reports);
/* Returns a USDPreviewSurface token name for a given Blender shader Socket name,

View File

@@ -153,11 +153,11 @@ void USDGenericMeshWriter::write_custom_data(const Object *obj,
{
const bke::AttributeAccessor attributes = mesh->attributes();
char *active_set_name = nullptr;
char *active_uvmap_name = nullptr;
const int active_uv_set_index = CustomData_get_render_layer_index(&mesh->corner_data,
CD_PROP_FLOAT2);
if (active_uv_set_index != -1) {
active_set_name = mesh->corner_data.layers[active_uv_set_index].name;
active_uvmap_name = mesh->corner_data.layers[active_uv_set_index].name;
}
attributes.for_all(
@@ -196,7 +196,7 @@ void USDGenericMeshWriter::write_custom_data(const Object *obj,
/* UV Data. */
if (meta_data.domain == bke::AttrDomain::Corner && meta_data.data_type == CD_PROP_FLOAT2) {
if (usd_export_context_.export_params.export_uvmaps) {
this->write_uv_data(mesh, usd_mesh, attribute_id, active_set_name);
this->write_uv_data(mesh, usd_mesh, attribute_id, active_uvmap_name);
}
}
@@ -275,7 +275,7 @@ void USDGenericMeshWriter::write_generic_data(const Mesh *mesh,
void USDGenericMeshWriter::write_uv_data(const Mesh *mesh,
pxr::UsdGeomMesh usd_mesh,
const bke::AttributeIDRef &attribute_id,
const char * /*active_set_name*/)
const char *active_uvmap_name)
{
const VArray<float2> buffer = *mesh->attributes().lookup<float2>(attribute_id,
bke::AttrDomain::Corner);
@@ -283,9 +283,18 @@ void USDGenericMeshWriter::write_uv_data(const Mesh *mesh,
return;
}
/* Optionally rename active UV map to "st", to follow USD conventions
* and better work with MaterialX shader nodes. */
const blender::StringRef name = usd_export_context_.export_params.rename_uvmaps &&
active_uvmap_name &&
(blender::StringRef(active_uvmap_name) ==
attribute_id.name()) ?
"st" :
attribute_id.name();
const pxr::UsdTimeCode timecode = get_export_time_code();
const pxr::TfToken pv_name(
make_safe_name(attribute_id.name(), usd_export_context_.export_params.allow_unicode));
make_safe_name(name, usd_export_context_.export_params.allow_unicode));
const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar(

View File

@@ -99,6 +99,7 @@ struct USDExportParams {
bool export_animation = false;
bool export_hair = true;
bool export_uvmaps = true;
bool rename_uvmaps = true;
bool export_normals = true;
bool export_mesh_colors = true;
bool export_materials = true;

View File

@@ -19,10 +19,10 @@ GroupNodeParser::GroupNodeParser(MaterialX::GraphElement *graph,
const bNodeSocket *socket_out,
NodeItem::Type to_type,
GroupNodeParser *group_parser,
ExportImageFunction export_image_fn,
ExportParams export_params,
bool use_group_default)
: NodeParser(
graph, depsgraph, material, node, socket_out, to_type, group_parser, export_image_fn),
graph, depsgraph, material, node, socket_out, to_type, group_parser, export_params),
use_group_default_(use_group_default)
{
}
@@ -56,7 +56,7 @@ NodeItem GroupNodeParser::compute()
socket_out_,
to_type_,
this,
export_image_fn_,
export_params_,
use_group_default_)
.compute_full();

View File

@@ -28,7 +28,7 @@ class GroupNodeParser : public NodeParser {
const bNodeSocket *socket_out,
NodeItem::Type to_type,
GroupNodeParser *group_parser,
ExportImageFunction export_image_fn,
ExportParams export_params,
bool use_group_default);
NodeItem compute() override;
NodeItem compute_full() override;

View File

@@ -52,7 +52,7 @@ class DefaultMaterialNodeParser : public NodeParser {
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
Material *material,
const std::string &material_name,
ExportImageFunction export_image_fn)
const ExportParams &export_params)
{
CLOG_INFO(LOG_MATERIALX_SHADER, 0, "Material: %s", material->id.name);
@@ -69,7 +69,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
NodeItem::Type::Material,
nullptr,
NodeItem(doc.get()),
export_image_fn};
export_params};
output_node->typeinfo->materialx_fn(&data, output_node, nullptr);
output_item = data.result;
}
@@ -81,7 +81,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
nullptr,
NodeItem::Type::Material,
nullptr,
export_image_fn)
export_params)
.compute_error();
}
}
@@ -93,7 +93,7 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
nullptr,
NodeItem::Type::Material,
nullptr,
export_image_fn)
export_params)
.compute();
}

View File

@@ -16,15 +16,17 @@ struct Main;
struct Material;
struct Scene;
class ExportImageFunction;
namespace blender::nodes::materialx {
using ExportImageFunction = std::function<std::string(Main *, Scene *, Image *, ImageUser *)>;
struct ExportParams {
std::function<std::string(Main *, Scene *, Image *, ImageUser *)> image_fn;
std::string new_active_uvmap_name;
std::string original_active_uvmap_name;
};
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
Material *material,
const std::string &material_name,
ExportImageFunction export_image_fn);
const ExportParams &export_params);
} // namespace blender::nodes::materialx

View File

@@ -25,7 +25,7 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph,
const bNodeSocket *socket_out,
NodeItem::Type to_type,
GroupNodeParser *group_parser,
ExportImageFunction export_image_fn)
const ExportParams &export_params)
: graph_(graph),
depsgraph_(depsgraph),
material_(material),
@@ -33,7 +33,7 @@ NodeParser::NodeParser(MaterialX::GraphElement *graph,
socket_out_(socket_out),
to_type_(to_type),
group_parser_(group_parser),
export_image_fn_(export_image_fn)
export_params_(export_params)
{
}
@@ -170,7 +170,7 @@ NodeItem NodeParser::empty() const
return NodeItem(graph_);
}
NodeItem NodeParser::texcoord_node(NodeItem::Type type)
NodeItem NodeParser::texcoord_node(NodeItem::Type type, const std::string &attribute_name)
{
BLI_assert(ELEM(type, NodeItem::Type::Vector2, NodeItem::Type::Vector3));
std::string name = TEXCOORD_NODE_NAME;
@@ -180,7 +180,18 @@ NodeItem NodeParser::texcoord_node(NodeItem::Type type)
NodeItem res = empty();
res.node = graph_->getNode(name);
if (!res.node) {
res = create_node("texcoord", type);
/* TODO: Use "Pref" generated texture coordinates for 3D, but needs
* work in USD and Hydra mesh export. */
const bool is_active_uvmap = attribute_name == "" ||
attribute_name == export_params_.original_active_uvmap_name;
if (export_params_.new_active_uvmap_name == "st" && is_active_uvmap) {
res = create_node("texcoord", type);
}
else {
const std::string &geomprop = (is_active_uvmap) ? export_params_.new_active_uvmap_name :
attribute_name;
res = create_node("geompropvalue", type, {{"geomprop", val(geomprop)}});
}
res.node->setName(name);
}
return res;
@@ -249,7 +260,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket,
link->fromsock,
to_type,
group_parser_,
export_image_fn_,
export_params_,
use_group_default)
.compute_full();
}
@@ -261,7 +272,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket,
link->fromsock,
to_type,
group_parser_,
export_image_fn_,
export_params_,
use_group_default)
.compute_full();
}
@@ -275,7 +286,7 @@ NodeItem NodeParser::get_input_link(const bNodeSocket &socket,
}
NodeParserData data = {
graph_, depsgraph_, material_, to_type, group_parser_, empty(), export_image_fn_};
graph_, depsgraph_, material_, to_type, group_parser_, empty(), export_params_};
from_node->typeinfo->materialx_fn(&data, const_cast<bNode *>(from_node), link->fromsock);
return data.result;
}

View File

@@ -32,7 +32,7 @@ class NodeParser {
const bNodeSocket *socket_out_;
NodeItem::Type to_type_;
GroupNodeParser *group_parser_;
ExportImageFunction export_image_fn_;
ExportParams export_params_;
public:
NodeParser(MaterialX::GraphElement *graph,
@@ -42,7 +42,7 @@ class NodeParser {
const bNodeSocket *socket_out,
NodeItem::Type to_type,
GroupNodeParser *group_parser,
ExportImageFunction export_image_fn);
const ExportParams &export_params);
virtual ~NodeParser() = default;
virtual NodeItem compute() = 0;
@@ -66,7 +66,8 @@ class NodeParser {
NodeItem get_input_value(int index, NodeItem::Type to_type);
NodeItem empty() const;
template<class T> NodeItem val(const T &data) const;
NodeItem texcoord_node(NodeItem::Type type = NodeItem::Type::Vector2);
NodeItem texcoord_node(NodeItem::Type type = NodeItem::Type::Vector2,
const std::string &attribute_name = "");
private:
NodeItem get_default(const bNodeSocket &socket, NodeItem::Type to_type);
@@ -104,7 +105,7 @@ struct NodeParserData {
NodeItem::Type to_type;
GroupNodeParser *group_parser;
NodeItem result;
ExportImageFunction export_image_fn;
ExportParams export_params;
};
#define NODE_SHADER_MATERIALX_BEGIN \
@@ -131,7 +132,7 @@ struct NodeParserData {
out, \
d->to_type, \
d->group_parser, \
d->export_image_fn) \
d->export_params) \
.compute_full(); \
}

View File

@@ -142,10 +142,10 @@ NODE_SHADER_MATERIALX_BEGIN
NodeTexEnvironment *tex_env = static_cast<NodeTexEnvironment *>(node_->storage);
std::string image_path = image->id.name;
if (export_image_fn_) {
if (export_params_.image_fn) {
Scene *scene = DEG_get_input_scene(depsgraph_);
Main *bmain = DEG_get_bmain(depsgraph_);
image_path = export_image_fn_(bmain, scene, image, &tex_env->iuser);
image_path = export_params_.image_fn(bmain, scene, image, &tex_env->iuser);
}
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2);

View File

@@ -190,10 +190,10 @@ NODE_SHADER_MATERIALX_BEGIN
NodeTexImage *tex_image = static_cast<NodeTexImage *>(node_->storage);
std::string image_path = image->id.name;
if (export_image_fn_) {
if (export_params_.image_fn) {
Scene *scene = DEG_get_input_scene(depsgraph_);
Main *bmain = DEG_get_bmain(depsgraph_);
image_path = export_image_fn_(bmain, scene, image, &tex_image->iuser);
image_path = export_params_.image_fn(bmain, scene, image, &tex_image->iuser);
}
NodeItem vector = get_input_link("Vector", NodeItem::Type::Vector2);

View File

@@ -76,10 +76,9 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
/* NODE: "From Instances" not implemented
* UV selection not implemented
*/
NodeItem res = texcoord_node();
/* NODE: "From Instances" not implemented */
NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node_->storage);
NodeItem res = texcoord_node(NodeItem::Type::Vector2, attr->uv_map);
return res;
}
#endif