diff options
author | makowalski <makowalski@nvidia.com> | 2021-03-06 03:56:07 +0300 |
---|---|---|
committer | makowalski <makowalski@nvidia.com> | 2021-03-06 03:56:07 +0300 |
commit | f47fa1c8376d81120c84e569873257221091449a (patch) | |
tree | bc8935c4c90c0f38ad67ce2a206a37ee1311ac3a /source | |
parent | 14fbb8b0718e2085d4702712a4577a67000f00ef (diff) |
USD Import format fixes.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/io/usd/intern/usd_reader_material.cc | 764 | ||||
-rw-r--r-- | source/blender/io/usd/intern/usd_reader_material.h | 2 |
2 files changed, 383 insertions, 383 deletions
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc index 8a8f5506ba1..acac2f49df2 100644 --- a/source/blender/io/usd/intern/usd_reader_material.cc +++ b/source/blender/io/usd/intern/usd_reader_material.cc @@ -188,390 +188,390 @@ void compute_node_loc( } // namespace - USDMaterialReader::USDMaterialReader(const USDImportParams ¶ms, Main *bmain) - : m_params(params), bmain_(bmain) - { - } - - Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_material) const - { - if (!(bmain_ && usd_material)) { - return nullptr; - } +USDMaterialReader::USDMaterialReader(const USDImportParams ¶ms, Main *bmain) + : m_params(params), bmain_(bmain) +{ +} + +Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_material) const +{ + if (!(bmain_ && usd_material)) { + return nullptr; + } + + std::string mtl_name = usd_material.GetPrim().GetName().GetString().c_str(); + + /* Create the material. */ + Material *mtl = BKE_material_add(bmain_, mtl_name.c_str()); + + /* Optionally, create shader nodes to represent a UsdPreviewSurface. */ + if (m_params.import_usd_preview) { + import_usd_preview(mtl, usd_material); + } + + return mtl; +} + +/* Convert a UsdPreviewSurface shader network to Blender nodes. + * The logic doesn't yet handle converting arbitrary prim var reader nodes. */ + +void USDMaterialReader::import_usd_preview(Material *mtl, + const pxr::UsdShadeMaterial &usd_material) const +{ + if (!usd_material) { + return; + } + + /* Get the surface shader. */ + pxr::UsdShadeShader surf_shader = usd_material.ComputeSurfaceSource(); + + if (surf_shader) { + /* Check if we have a UsdPreviewSurface shader. */ + pxr::TfToken shader_id; + if (surf_shader.GetShaderId(&shader_id) && shader_id == usdtokens::UsdPreviewSurface) { + import_usd_preview(mtl, surf_shader); + } + } +} + +/* Create the Principled BSDF shader node network. */ +void USDMaterialReader::import_usd_preview(Material *mtl, + const pxr::UsdShadeShader &usd_shader) const +{ + if (!(bmain_ && mtl && usd_shader)) { + return; + } + + /* Create the Material's node tree containing the principled + * and output shader. */ + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree"); + mtl->nodetree = ntree; + mtl->use_nodes = true; + + bNode *principled = add_node(NULL, ntree, SH_NODE_BSDF_PRINCIPLED, 0.0f, 300.0f); + + if (!principled) { + std::cerr << "ERROR: Couldn't create SH_NODE_BSDF_PRINCIPLED node for USD shader " + << usd_shader.GetPath() << std::endl; + return; + } + + bNode *output = add_node(NULL, ntree, SH_NODE_OUTPUT_MATERIAL, 300.0f, 300.0f); + + if (!output) { + std::cerr << "ERROR: Couldn't create SH_NODE_OUTPUT_MATERIAL node for USD shader " + << usd_shader.GetPath() << std::endl; + return; + } + + link_nodes(ntree, principled, "BSDF", output, "Surface"); + + /* Set up the principled shader inputs. */ + + /* The following keep track of the locations for adding + * input nodes. */ + + NodePlacementContext context(0.0f, 300.0); + int column = 0; + + /* Set the principled shader inputs. */ + + if (pxr::UsdShadeInput diffuse_input = usd_shader.GetInput(usdtokens::diffuseColor)) { + set_node_input(diffuse_input, principled, "Base Color", ntree, column, context); + } + + if (pxr::UsdShadeInput emissive_input = usd_shader.GetInput(usdtokens::emissiveColor)) { + set_node_input(emissive_input, principled, "Emission", ntree, column, context); + } + + if (pxr::UsdShadeInput specular_input = usd_shader.GetInput(usdtokens::specularColor)) { + set_node_input(specular_input, principled, "Specular", ntree, column, context); + } + + if (pxr::UsdShadeInput metallic_input = usd_shader.GetInput(usdtokens::metallic)) { + ; + set_node_input(metallic_input, principled, "Metallic", ntree, column, context); + } + + if (pxr::UsdShadeInput roughness_input = usd_shader.GetInput(usdtokens::roughness)) { + set_node_input(roughness_input, principled, "Roughness", ntree, column, context); + } + + if (pxr::UsdShadeInput clearcoat_input = usd_shader.GetInput(usdtokens::clearcoat)) { + set_node_input(clearcoat_input, principled, "Clearcoat", ntree, column, context); + } + + if (pxr::UsdShadeInput clearcoat_roughness_input = usd_shader.GetInput( + usdtokens::clearcoatRoughness)) { + set_node_input( + clearcoat_roughness_input, principled, "Clearcoat Roughness", ntree, column, context); + } - std::string mtl_name = usd_material.GetPrim().GetName().GetString().c_str(); - - /* Create the material. */ - Material *mtl = BKE_material_add(bmain_, mtl_name.c_str()); - - /* Optionally, create shader nodes to represent a UsdPreviewSurface. */ - if (m_params.import_usd_preview) { - import_usd_preview(mtl, usd_material); - } - - return mtl; - } - - /* Convert a UsdPreviewSurface shader network to Blender nodes. - * The logic doesn't yet handle converting arbitrary prim var reader nodes. */ - - void USDMaterialReader::import_usd_preview(Material *mtl, - const pxr::UsdShadeMaterial &usd_material) const - { - if (!usd_material) { - return; - } + if (pxr::UsdShadeInput opacity_input = usd_shader.GetInput(usdtokens::opacity)) { + set_node_input(opacity_input, principled, "Alpha", ntree, column, context); + } + + if (pxr::UsdShadeInput ior_input = usd_shader.GetInput(usdtokens::ior)) { + set_node_input(ior_input, principled, "IOR", ntree, column, context); + } + + if (pxr::UsdShadeInput normal_input = usd_shader.GetInput(usdtokens::normal)) { + set_node_input(normal_input, principled, "Normal", ntree, column, context); + } - /* Get the surface shader. */ - pxr::UsdShadeShader surf_shader = usd_material.ComputeSurfaceSource(); + nodeSetActive(ntree, output); - if (surf_shader) { - /* Check if we have a UsdPreviewSurface shader. */ - pxr::TfToken shader_id; - if (surf_shader.GetShaderId(&shader_id) && shader_id == usdtokens::UsdPreviewSurface) { - import_usd_preview(mtl, surf_shader); - } - } - } - - /* Create the Principled BSDF shader node network. */ - void USDMaterialReader::import_usd_preview(Material *mtl, - const pxr::UsdShadeShader &usd_shader) const - { - if (!(bmain_ && mtl && usd_shader)) { - return; - } - - /* Create the Material's node tree containing the principled - * and output shader. */ - - bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree"); - mtl->nodetree = ntree; - mtl->use_nodes = true; - - bNode *principled = add_node(NULL, ntree, SH_NODE_BSDF_PRINCIPLED, 0.0f, 300.0f); - - if (!principled) { - std::cerr << "ERROR: Couldn't create SH_NODE_BSDF_PRINCIPLED node for USD shader " - << usd_shader.GetPath() << std::endl; - return; - } - - bNode *output = add_node(NULL, ntree, SH_NODE_OUTPUT_MATERIAL, 300.0f, 300.0f); - - if (!output) { - std::cerr << "ERROR: Couldn't create SH_NODE_OUTPUT_MATERIAL node for USD shader " - << usd_shader.GetPath() << std::endl; - return; - } - - link_nodes(ntree, principled, "BSDF", output, "Surface"); - - /* Set up the principled shader inputs. */ - - /* The following keep track of the locations for adding - * input nodes. */ - - NodePlacementContext context(0.0f, 300.0); - int column = 0; - - /* Set the principled shader inputs. */ - - if (pxr::UsdShadeInput diffuse_input = usd_shader.GetInput(usdtokens::diffuseColor)) { - set_node_input(diffuse_input, principled, "Base Color", ntree, column, context); - } - - if (pxr::UsdShadeInput emissive_input = usd_shader.GetInput(usdtokens::emissiveColor)) { - set_node_input(emissive_input, principled, "Emission", ntree, column, context); - } - - if (pxr::UsdShadeInput specular_input = usd_shader.GetInput(usdtokens::specularColor)) { - set_node_input(specular_input, principled, "Specular", ntree, column, context); - } - - if (pxr::UsdShadeInput metallic_input = usd_shader.GetInput(usdtokens::metallic)) { - ; - set_node_input(metallic_input, principled, "Metallic", ntree, column, context); - } - - if (pxr::UsdShadeInput roughness_input = usd_shader.GetInput(usdtokens::roughness)) { - set_node_input(roughness_input, principled, "Roughness", ntree, column, context); - } - - if (pxr::UsdShadeInput clearcoat_input = usd_shader.GetInput(usdtokens::clearcoat)) { - set_node_input(clearcoat_input, principled, "Clearcoat", ntree, column, context); - } - - if (pxr::UsdShadeInput clearcoat_roughness_input = usd_shader.GetInput( - usdtokens::clearcoatRoughness)) { - set_node_input( - clearcoat_roughness_input, principled, "Clearcoat Roughness", ntree, column, context); - } - - if (pxr::UsdShadeInput opacity_input = usd_shader.GetInput(usdtokens::opacity)) { - set_node_input(opacity_input, principled, "Alpha", ntree, column, context); - } - - if (pxr::UsdShadeInput ior_input = usd_shader.GetInput(usdtokens::ior)) { - set_node_input(ior_input, principled, "IOR", ntree, column, context); - } - - if (pxr::UsdShadeInput normal_input = usd_shader.GetInput(usdtokens::normal)) { - set_node_input(normal_input, principled, "Normal", ntree, column, context); - } - - nodeSetActive(ntree, output); - - // Optionally, set the material blend mode. - - if (m_params.set_material_blend) { - float opacity_threshold = 0.0f; - if (needs_blend(usd_shader, opacity_threshold)) { - if (opacity_threshold > 0.0f) { - mtl->blend_method = MA_BM_CLIP; - mtl->alpha_threshold = opacity_threshold; - } - else { - mtl->blend_method = MA_BM_BLEND; - } - } - } - } - - /* Convert the given USD shader input to an input on the given node. */ - void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input, - bNode *dest_node, - const char *dest_socket_name, - bNodeTree *ntree, - int column, - NodePlacementContext &r_ctx) const - { - if (!(usd_input && dest_node)) { - return; - } - - if (usd_input.HasConnectedSource()) { - pxr::UsdShadeConnectableAPI source; - pxr::TfToken source_name; - pxr::UsdShadeAttributeType source_type; - - usd_input.GetConnectedSource(&source, &source_name, &source_type); - - if (!(source && source.IsShader())) { - return; - } - - pxr::UsdShadeShader source_shader(source.GetPrim()); - - if (!source_shader) { - return; - } - - pxr::TfToken shader_id; - if (!source_shader.GetShaderId(&shader_id)) { - std::cerr << "ERROR: couldn't get shader id for source shader " - << source_shader.GetPrim().GetPath() << std::endl; - return; - } - - /* For now, only convert UsdUVTexture and UsdPrimvarReader_float2 inputs. */ - if (shader_id == usdtokens::UsdUVTexture) { - - if (strcmp(dest_socket_name, "Normal") == 0) { - - // The normal texture input requires creating a normal map node. - float locx = 0.0f; - float locy = 0.0f; - compute_node_loc(column + 1, 300.0, locx, locy, r_ctx); - - bNode *normal_map = add_node(NULL, ntree, SH_NODE_NORMAL_MAP, locx, locy); - - // Currently, the Normal Map node has Tangent Space as the default, - // which is what we need, so we don't need to explicitly set it. - - // Connect the Normal Map to the Normal input. - link_nodes(ntree, normal_map, "Normal", dest_node, "Normal"); - - // Now, create the Texture Image node input to the Normal Map "Color" input. - convert_usd_uv_texture( - source_shader, source_name, normal_map, "Color", ntree, column + 2, r_ctx); - } - else { - convert_usd_uv_texture( - source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx); - } - } - else if (shader_id == usdtokens::UsdPrimvarReader_float2) { - convert_usd_primvar_reader_float2( - source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx); - } - } - else { - bNodeSocket *sock = nodeFindSocket(dest_node, SOCK_IN, dest_socket_name); - if (!sock) { - std::cerr << "ERROR: couldn't get destination node socket " << dest_socket_name << std::endl; - return; - } - - pxr::VtValue val; - if (!usd_input.Get(&val)) { - std::cerr << "ERROR: couldn't get value for usd shader input " - << usd_input.GetPrim().GetPath() << std::endl; - return; - } - - switch (sock->type) { - case SOCK_FLOAT: - if (val.IsHolding<float>()) { - ((bNodeSocketValueFloat *)sock->default_value)->value = val.UncheckedGet<float>(); - } - else if (val.IsHolding<pxr::GfVec3f>()) { - pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>(); - float average = (v3f[0] + v3f[1] + v3f[2]) / 3.0f; - ((bNodeSocketValueFloat *)sock->default_value)->value = average; - } - break; - case SOCK_RGBA: - if (val.IsHolding<pxr::GfVec3f>()) { - pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>(); - copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, v3f.data()); - } - break; - case SOCK_VECTOR: - if (val.IsHolding<pxr::GfVec3f>()) { - pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>(); - copy_v3_v3(((bNodeSocketValueVector *)sock->default_value)->value, v3f.data()); - } - else if (val.IsHolding<pxr::GfVec2f>()) { - pxr::GfVec2f v2f = val.UncheckedGet<pxr::GfVec2f>(); - copy_v2_v2(((bNodeSocketValueVector *)sock->default_value)->value, v2f.data()); - } - break; - default: - std::cerr << "WARNING: unexpected type " << sock->idname << " for destination node socket " - << dest_socket_name << std::endl; - break; - } - } - } - - void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_shader, - const pxr::TfToken &usd_source_name, - bNode *dest_node, - const char *dest_socket_name, - bNodeTree *ntree, - int column, - NodePlacementContext &r_ctx) const - { - if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_) { - return; - } - - float locx = 0.0f; - float locy = 0.0f; - compute_node_loc(column, 300.0, locx, locy, r_ctx); - - // Create the Texture Image node. - bNode *tex_image = add_node(NULL, ntree, SH_NODE_TEX_IMAGE, locx, locy); - - if (!tex_image) { - std::cerr << "ERROR: Couldn't create SH_NODE_TEX_IMAGE for node input " << dest_socket_name - << std::endl; - return; - } - - // Try to load the texture image. - pxr::UsdShadeInput file_input = usd_shader.GetInput(usdtokens::file); - if (file_input) { - - pxr::VtValue file_val; - if (file_input.Get(&file_val) && file_val.IsHolding<pxr::SdfAssetPath>()) { - const pxr::SdfAssetPath &asset_path = file_val.Get<pxr::SdfAssetPath>(); - std::string file_path = asset_path.GetResolvedPath(); - if (!file_path.empty()) { - const char *im_file = file_path.c_str(); - Image *image = BKE_image_load_exists(bmain_, im_file); - if (image) { - tex_image->id = &image->id; - - // Set texture color space. - // TODO(makowalski): For now, just checking for RAW color space, - // assuming sRGB otherwise, but more complex logic might be - // required if the color space is "auto". - pxr::TfToken colorSpace = file_input.GetAttr().GetColorSpace(); - if (colorSpace == usdtokens::RAW || colorSpace == usdtokens::raw) { - STRNCPY(image->colorspace_settings.name, "Raw"); - } - } - else { - std::cerr << "WARNING: Couldn't open image file '" << im_file - << "' for Texture Image node." << std::endl; - } - } - else { - std::cerr << "WARNING: Couldn't resolve image asset '" << asset_path - << "' for Texture Image node." << std::endl; - } - } - } - - // Connect to destination node input. - - // Get the source socket name. - std::string source_socket_name = usd_source_name == usdtokens::a ? "Alpha" : "Color"; - - link_nodes(ntree, tex_image, source_socket_name.c_str(), dest_node, dest_socket_name); - - // Connect the texture image node "Vector" input. - if (pxr::UsdShadeInput st_input = usd_shader.GetInput(usdtokens::st)) { - set_node_input(st_input, tex_image, "Vector", ntree, column, r_ctx); - } - } - - /* This function creates a Blender UV Map node, under the simplifying assumption that - * UsdPrimvarReader_float2 shaders output UV coordinates. - * TODO(makowalski): investigate supporting conversion to other Blender node types - * (e.g., Attribute Nodes) if needed. */ - void USDMaterialReader::convert_usd_primvar_reader_float2(const pxr::UsdShadeShader &usd_shader, - const pxr::TfToken &usd_source_name, - bNode *dest_node, - const char *dest_socket_name, - bNodeTree *ntree, - int column, - NodePlacementContext &r_ctx) const - { - if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_) { - return; - } - - float locx = 0.0f; - float locy = 0.0f; - compute_node_loc(column, 300.0f, locx, locy, r_ctx); - - // Create the UV Map node. - bNode *uv_map = add_node(NULL, ntree, SH_NODE_UVMAP, locx, locy); - - if (!uv_map) { - std::cerr << "ERROR: Couldn't create SH_NODE_UVMAP for node input " << dest_socket_name - << std::endl; - return; - } - - // Set the texmap name. - pxr::UsdShadeInput varname_input = usd_shader.GetInput(usdtokens::varname); - if (varname_input) { - pxr::VtValue varname_val; - if (varname_input.Get(&varname_val) && varname_val.IsHolding<pxr::TfToken>()) { - std::string varname = varname_val.Get<pxr::TfToken>().GetString(); - if (!varname.empty()) { - NodeShaderUVMap *storage = (NodeShaderUVMap *)uv_map->storage; - BLI_strncpy(storage->uv_map, varname.c_str(), sizeof(storage->uv_map)); - } - } - } - - // Connect to destination node input. - link_nodes(ntree, uv_map, "UV", dest_node, dest_socket_name); - } + // Optionally, set the material blend mode. + + if (m_params.set_material_blend) { + float opacity_threshold = 0.0f; + if (needs_blend(usd_shader, opacity_threshold)) { + if (opacity_threshold > 0.0f) { + mtl->blend_method = MA_BM_CLIP; + mtl->alpha_threshold = opacity_threshold; + } + else { + mtl->blend_method = MA_BM_BLEND; + } + } + } +} + +/* Convert the given USD shader input to an input on the given node. */ +void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input, + bNode *dest_node, + const char *dest_socket_name, + bNodeTree *ntree, + int column, + NodePlacementContext &r_ctx) const +{ + if (!(usd_input && dest_node)) { + return; + } + + if (usd_input.HasConnectedSource()) { + pxr::UsdShadeConnectableAPI source; + pxr::TfToken source_name; + pxr::UsdShadeAttributeType source_type; + + usd_input.GetConnectedSource(&source, &source_name, &source_type); + + if (!(source && source.IsShader())) { + return; + } + + pxr::UsdShadeShader source_shader(source.GetPrim()); + + if (!source_shader) { + return; + } + + pxr::TfToken shader_id; + if (!source_shader.GetShaderId(&shader_id)) { + std::cerr << "ERROR: couldn't get shader id for source shader " + << source_shader.GetPrim().GetPath() << std::endl; + return; + } + + /* For now, only convert UsdUVTexture and UsdPrimvarReader_float2 inputs. */ + if (shader_id == usdtokens::UsdUVTexture) { + + if (strcmp(dest_socket_name, "Normal") == 0) { + + // The normal texture input requires creating a normal map node. + float locx = 0.0f; + float locy = 0.0f; + compute_node_loc(column + 1, 300.0, locx, locy, r_ctx); + + bNode *normal_map = add_node(NULL, ntree, SH_NODE_NORMAL_MAP, locx, locy); + + // Currently, the Normal Map node has Tangent Space as the default, + // which is what we need, so we don't need to explicitly set it. + + // Connect the Normal Map to the Normal input. + link_nodes(ntree, normal_map, "Normal", dest_node, "Normal"); + + // Now, create the Texture Image node input to the Normal Map "Color" input. + convert_usd_uv_texture( + source_shader, source_name, normal_map, "Color", ntree, column + 2, r_ctx); + } + else { + convert_usd_uv_texture( + source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx); + } + } + else if (shader_id == usdtokens::UsdPrimvarReader_float2) { + convert_usd_primvar_reader_float2( + source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx); + } + } + else { + bNodeSocket *sock = nodeFindSocket(dest_node, SOCK_IN, dest_socket_name); + if (!sock) { + std::cerr << "ERROR: couldn't get destination node socket " << dest_socket_name << std::endl; + return; + } + + pxr::VtValue val; + if (!usd_input.Get(&val)) { + std::cerr << "ERROR: couldn't get value for usd shader input " + << usd_input.GetPrim().GetPath() << std::endl; + return; + } + + switch (sock->type) { + case SOCK_FLOAT: + if (val.IsHolding<float>()) { + ((bNodeSocketValueFloat *)sock->default_value)->value = val.UncheckedGet<float>(); + } + else if (val.IsHolding<pxr::GfVec3f>()) { + pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>(); + float average = (v3f[0] + v3f[1] + v3f[2]) / 3.0f; + ((bNodeSocketValueFloat *)sock->default_value)->value = average; + } + break; + case SOCK_RGBA: + if (val.IsHolding<pxr::GfVec3f>()) { + pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>(); + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, v3f.data()); + } + break; + case SOCK_VECTOR: + if (val.IsHolding<pxr::GfVec3f>()) { + pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>(); + copy_v3_v3(((bNodeSocketValueVector *)sock->default_value)->value, v3f.data()); + } + else if (val.IsHolding<pxr::GfVec2f>()) { + pxr::GfVec2f v2f = val.UncheckedGet<pxr::GfVec2f>(); + copy_v2_v2(((bNodeSocketValueVector *)sock->default_value)->value, v2f.data()); + } + break; + default: + std::cerr << "WARNING: unexpected type " << sock->idname << " for destination node socket " + << dest_socket_name << std::endl; + break; + } + } +} + +void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_shader, + const pxr::TfToken &usd_source_name, + bNode *dest_node, + const char *dest_socket_name, + bNodeTree *ntree, + int column, + NodePlacementContext &r_ctx) const +{ + if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_) { + return; + } + + float locx = 0.0f; + float locy = 0.0f; + compute_node_loc(column, 300.0, locx, locy, r_ctx); + + // Create the Texture Image node. + bNode *tex_image = add_node(NULL, ntree, SH_NODE_TEX_IMAGE, locx, locy); + + if (!tex_image) { + std::cerr << "ERROR: Couldn't create SH_NODE_TEX_IMAGE for node input " << dest_socket_name + << std::endl; + return; + } + + // Try to load the texture image. + pxr::UsdShadeInput file_input = usd_shader.GetInput(usdtokens::file); + if (file_input) { + + pxr::VtValue file_val; + if (file_input.Get(&file_val) && file_val.IsHolding<pxr::SdfAssetPath>()) { + const pxr::SdfAssetPath &asset_path = file_val.Get<pxr::SdfAssetPath>(); + std::string file_path = asset_path.GetResolvedPath(); + if (!file_path.empty()) { + const char *im_file = file_path.c_str(); + Image *image = BKE_image_load_exists(bmain_, im_file); + if (image) { + tex_image->id = &image->id; + + // Set texture color space. + // TODO(makowalski): For now, just checking for RAW color space, + // assuming sRGB otherwise, but more complex logic might be + // required if the color space is "auto". + pxr::TfToken colorSpace = file_input.GetAttr().GetColorSpace(); + if (colorSpace == usdtokens::RAW || colorSpace == usdtokens::raw) { + STRNCPY(image->colorspace_settings.name, "Raw"); + } + } + else { + std::cerr << "WARNING: Couldn't open image file '" << im_file + << "' for Texture Image node." << std::endl; + } + } + else { + std::cerr << "WARNING: Couldn't resolve image asset '" << asset_path + << "' for Texture Image node." << std::endl; + } + } + } + + // Connect to destination node input. + + // Get the source socket name. + std::string source_socket_name = usd_source_name == usdtokens::a ? "Alpha" : "Color"; + + link_nodes(ntree, tex_image, source_socket_name.c_str(), dest_node, dest_socket_name); + + // Connect the texture image node "Vector" input. + if (pxr::UsdShadeInput st_input = usd_shader.GetInput(usdtokens::st)) { + set_node_input(st_input, tex_image, "Vector", ntree, column, r_ctx); + } +} + +/* This function creates a Blender UV Map node, under the simplifying assumption that + * UsdPrimvarReader_float2 shaders output UV coordinates. + * TODO(makowalski): investigate supporting conversion to other Blender node types + * (e.g., Attribute Nodes) if needed. */ +void USDMaterialReader::convert_usd_primvar_reader_float2(const pxr::UsdShadeShader &usd_shader, + const pxr::TfToken &usd_source_name, + bNode *dest_node, + const char *dest_socket_name, + bNodeTree *ntree, + int column, + NodePlacementContext &r_ctx) const +{ + if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_) { + return; + } + + float locx = 0.0f; + float locy = 0.0f; + compute_node_loc(column, 300.0f, locx, locy, r_ctx); + + // Create the UV Map node. + bNode *uv_map = add_node(NULL, ntree, SH_NODE_UVMAP, locx, locy); + + if (!uv_map) { + std::cerr << "ERROR: Couldn't create SH_NODE_UVMAP for node input " << dest_socket_name + << std::endl; + return; + } + + // Set the texmap name. + pxr::UsdShadeInput varname_input = usd_shader.GetInput(usdtokens::varname); + if (varname_input) { + pxr::VtValue varname_val; + if (varname_input.Get(&varname_val) && varname_val.IsHolding<pxr::TfToken>()) { + std::string varname = varname_val.Get<pxr::TfToken>().GetString(); + if (!varname.empty()) { + NodeShaderUVMap *storage = (NodeShaderUVMap *)uv_map->storage; + BLI_strncpy(storage->uv_map, varname.c_str(), sizeof(storage->uv_map)); + } + } + } + + // Connect to destination node input. + link_nodes(ntree, uv_map, "UV", dest_node, dest_socket_name); +} } // namespace blender::io::usd diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h index 7bdc06c7fb6..2ac87f1e482 100644 --- a/source/blender/io/usd/intern/usd_reader_material.h +++ b/source/blender/io/usd/intern/usd_reader_material.h @@ -69,7 +69,7 @@ struct NodePlacementContext { class USDMaterialReader { protected: - USDImportParams m_params; + USDImportParams m_params; Main *bmain_; |