Fix T103984: USD exports pass usdchecker
These changes were authored by Michael B Johnson (drwave). The default Blender USD export currently produces files that trigger errors in the usdchecker that ships with USD 22.11. The changes are: - Set the defaultPrim if no defaultPrim is set. This sets it to the first prim in the hierarchy which matches the behaviour of Pixar's referencing (where referencing a USD layer without a defaultPrim will pick the first prim) as well as matches the logic in Pixar's Maya USD exporter code. - Applies the MaterialBindingAPI to prims with material binding attributes. This is a relatively new requirement for USD as it will help for efficiency with upcoming changes to Hydra. - Removes the preview scope in the USD shader hierarchy, because it is no longer valid for shaders to have any non-container ancestors in their hierarchy up until the enclosing Material prim. Reviewed by: Michael Kowalski Differential Revision: https://developer.blender.org/D17041
This commit is contained in:
parent
4635dd6aed
commit
b67b84bd5d
Notes:
blender-bot
2023-02-14 06:42:53 +01:00
Referenced by issue #103984, fixes to have exported USD pass usdchecker
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <pxr/base/plug/registry.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/primRange.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usd/usdGeom/tokens.h>
|
||||
|
||||
|
@ -138,6 +140,17 @@ static void export_startjob(void *customdata,
|
|||
}
|
||||
|
||||
iter.release_writers();
|
||||
|
||||
/* Set the default prim if it doesn't exist */
|
||||
if (!usd_stage->GetDefaultPrim()) {
|
||||
/* Use TraverseAll since it's guaranteed to be depth first and will get the first top level
|
||||
* prim, and is less verbose than getting the PseudoRoot + iterating its children.*/
|
||||
for (auto prim : usd_stage->TraverseAll()) {
|
||||
usd_stage->SetDefaultPrim(prim);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
usd_stage->GetRootLayer()->Save();
|
||||
|
||||
/* Finish up by going back to the keyframe that was current before we started. */
|
||||
|
|
|
@ -60,7 +60,6 @@ static const pxr::TfToken out("out", pxr::TfToken::Immortal);
|
|||
static const pxr::TfToken normal("normal", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken ior("ior", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken file("file", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken preview("preview", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken raw("raw", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken sRGB("sRGB", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken sourceColorSpace("sourceColorSpace", pxr::TfToken::Immortal);
|
||||
|
@ -124,10 +123,6 @@ void create_usd_preview_surface_material(const USDExporterContext &usd_export_co
|
|||
return;
|
||||
}
|
||||
|
||||
/* Define a 'preview' scope beneath the material which will contain the preview shaders. */
|
||||
pxr::UsdGeomScope::Define(usd_export_context.stage,
|
||||
usd_material.GetPath().AppendChild(usdtokens::preview));
|
||||
|
||||
/* Default map when creating UV primvar reader shaders. */
|
||||
pxr::TfToken default_uv_sampler = default_uv.empty() ? cyclestokens::UVMap :
|
||||
pxr::TfToken(default_uv);
|
||||
|
@ -470,9 +465,8 @@ static pxr::UsdShadeShader create_usd_preview_shader(const USDExporterContext &u
|
|||
const char *name,
|
||||
const int type)
|
||||
{
|
||||
pxr::SdfPath shader_path = material.GetPath()
|
||||
.AppendChild(usdtokens::preview)
|
||||
.AppendChild(pxr::TfToken(pxr::TfMakeValidIdentifier(name)));
|
||||
pxr::SdfPath shader_path = material.GetPath().AppendChild(
|
||||
pxr::TfToken(pxr::TfMakeValidIdentifier(name)));
|
||||
pxr::UsdShadeShader shader = pxr::UsdShadeShader::Define(usd_export_context.stage, shader_path);
|
||||
|
||||
switch (type) {
|
||||
|
|
|
@ -350,7 +350,8 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
|
|||
* which is why we always bind the first material to the entire mesh. See
|
||||
* https://github.com/PixarAnimationStudios/USD/issues/542 for more info. */
|
||||
bool mesh_material_bound = false;
|
||||
pxr::UsdShadeMaterialBindingAPI material_binding_api(usd_mesh.GetPrim());
|
||||
auto mesh_prim = usd_mesh.GetPrim();
|
||||
pxr::UsdShadeMaterialBindingAPI material_binding_api(mesh_prim);
|
||||
for (int mat_num = 0; mat_num < context.object->totcol; mat_num++) {
|
||||
Material *material = BKE_object_material_get(context.object, mat_num + 1);
|
||||
if (material == nullptr) {
|
||||
|
@ -369,7 +370,13 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!mesh_material_bound) {
|
||||
if (mesh_material_bound) {
|
||||
/* USD will require that prims with material bindings have the MaterialBindingAPI applied
|
||||
* schema. While Bind() above will create the binding attribute, Apply() needs to be called as
|
||||
* well to add the MaterialBindingAPI schema to the prim itself.*/
|
||||
material_binding_api.Apply(mesh_prim);
|
||||
}
|
||||
else {
|
||||
/* Blender defaults to double-sided, but USD to single-sided. */
|
||||
usd_mesh.CreateDoubleSidedAttr(pxr::VtValue(true));
|
||||
}
|
||||
|
@ -396,7 +403,11 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
|
|||
|
||||
pxr::UsdGeomSubset usd_face_subset = material_binding_api.CreateMaterialBindSubset(
|
||||
material_name, face_indices);
|
||||
pxr::UsdShadeMaterialBindingAPI(usd_face_subset.GetPrim()).Bind(usd_material);
|
||||
auto subset_prim = usd_face_subset.GetPrim();
|
||||
auto subset_material_api = pxr::UsdShadeMaterialBindingAPI(subset_prim);
|
||||
subset_material_api.Bind(usd_material);
|
||||
/* Apply the MaterialBindingAPI applied schema, as required by USD.*/
|
||||
subset_material_api.Apply(subset_prim);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ TEST_F(UsdExportTest, usd_export_material)
|
|||
|
||||
const std::string prim_name = pxr::TfMakeValidIdentifier(bsdf_node->name);
|
||||
const pxr::UsdPrim bsdf_prim = stage->GetPrimAtPath(
|
||||
pxr::SdfPath("/_materials/Material/preview/" + prim_name));
|
||||
pxr::SdfPath("/_materials/Material/" + prim_name));
|
||||
|
||||
compare_blender_node_to_usd_prim(bsdf_node, bsdf_prim);
|
||||
|
||||
|
@ -305,7 +305,7 @@ TEST_F(UsdExportTest, usd_export_material)
|
|||
const std::string image_prim_name = pxr::TfMakeValidIdentifier(image_node->name);
|
||||
|
||||
const pxr::UsdPrim image_prim = stage->GetPrimAtPath(
|
||||
pxr::SdfPath("/_materials/Material/preview/" + image_prim_name));
|
||||
pxr::SdfPath("/_materials/Material/" + image_prim_name));
|
||||
|
||||
ASSERT_TRUE(bool(image_prim)) << "Unable to find Material prim from exported stage "
|
||||
<< output_filename;
|
||||
|
|
Loading…
Reference in New Issue