diff --git a/Changes b/Changes index 9605a88505..0820367d85 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,7 @@ Fixes - Fixed loading of skinned facevarying normals. - `lightLink` and `shadowLink` collections on UsdLuxLightAPI are no longer treated as sets. - Version.h : Fixed `*Version()` functions to return the runtime version of the library, not the version that client code was compiled with. Use the `CORTEX_*_VERSION` macros for compile time checks. +- IECoreUSD : Asset and volume paths now use `/` in the resolved path on all operating systems. This behavior can be disabled by setting the `IECOREUSD_FORCE_ASSET_PATH_FORWARD_SLASH` environment variable to a value of `0`. 10.5.9.2 (relative to 10.5.9.1) ======== diff --git a/contrib/IECoreUSD/src/IECoreUSD/DataAlgo.cpp b/contrib/IECoreUSD/src/IECoreUSD/DataAlgo.cpp index 6b4eca217e..436d534ae8 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/DataAlgo.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/DataAlgo.cpp @@ -49,6 +49,10 @@ IECORE_POP_DEFAULT_VISIBILITY #include "boost/unordered_map.hpp" +#ifdef _MSC_VER +#include +#endif + using namespace std; using namespace pxr; using namespace IECore; @@ -92,6 +96,19 @@ GeometricData::Interpretation interpretation( TfToken role ) return GeometricData::None; } +#ifdef _MSC_VER + +static const bool g_forceAssetPathForwardSlash = []() -> bool { + const char *c = getenv( "IECOREUSD_FORCE_ASSET_PATH_FORWARD_SLASH" ); + if( !c ) + { + return true; + } + return strcmp( c, "0" ); +}(); + +#endif + } // namespace @@ -142,9 +159,16 @@ IECore::DataPtr dataFromArray( const pxr::VtValue &value, GeometricData::Interpr IECore::DataPtr dataFromSdfAssetPath( const SdfAssetPath &assetPath, const pxr::UsdAttribute *attribute = nullptr ) { - if( assetPath.GetResolvedPath().size() || !assetPath.GetAssetPath().size() || !attribute ) + +#ifdef _MSC_VER + const std::string p = g_forceAssetPathForwardSlash ? std::filesystem::path( assetPath.GetResolvedPath() ).generic_string() : assetPath.GetResolvedPath(); +#else + const std::string p = assetPath.GetResolvedPath(); +#endif + + if( p.size() || !assetPath.GetAssetPath().size() || !attribute ) { - return new StringData( assetPath.GetResolvedPath() ); + return new StringData( p ); } // Path resolution failed, for a couple of possible reasons : @@ -168,9 +192,16 @@ IECore::DataPtr dataFromSdfAssetPath( const SdfAssetPath &assetPath, const pxr:: spec->GetLayer()->GetNumTimeSamplesForPath( spec->GetPath() ) ) { +#ifdef _MSC_VER + const std::string result = SdfComputeAssetPathRelativeToLayer( spec->GetLayer(), assetPath.GetAssetPath() ); + return new StringData( + g_forceAssetPathForwardSlash ? std::filesystem::path( result ).generic_string() : result + ); +#else return new StringData( SdfComputeAssetPathRelativeToLayer( spec->GetLayer(), assetPath.GetAssetPath() ) ); +#endif } } diff --git a/contrib/IECoreUSD/src/IECoreUSD/VolumeAlgo.cpp b/contrib/IECoreUSD/src/IECoreUSD/VolumeAlgo.cpp index 4a58cc6bc7..4984065721 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/VolumeAlgo.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/VolumeAlgo.cpp @@ -32,11 +32,13 @@ // ////////////////////////////////////////////////////////////////////////// +#include "IECoreUSD/DataAlgo.h" #include "IECoreUSD/ObjectAlgo.h" #include "IECoreVDB/VDBObject.h" #include "IECore/MessageHandler.h" +#include "IECore/SimpleTypedData.h" IECORE_PUSH_DEFAULT_VISIBILITY #include "pxr/usd/usdVol/volume.h" @@ -96,9 +98,8 @@ IECore::ObjectPtr readVolume( pxr::UsdVolVolume &volume, pxr::UsdTimeCode time, continue; } - SdfAssetPath fieldAssetPath; - fieldAsset.GetFilePathAttr().Get( &fieldAssetPath, time ); - const std::string fieldFileName = fieldAssetPath.GetResolvedPath(); + ConstDataPtr fieldFileNameData = DataAlgo::fromUSD( fieldAsset.GetFilePathAttr(), time ); + const std::string fieldFileName = static_cast( fieldFileNameData.get() )->readable(); if( fileName.empty() ) { diff --git a/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py b/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py index a66f11b6f8..9e944f9ab2 100644 --- a/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py +++ b/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py @@ -32,6 +32,8 @@ # ########################################################################## +import IECore + import importlib import os import math @@ -4371,5 +4373,30 @@ def testWriteToOpenScene( self ) : with self.assertRaisesRegex( RuntimeError, f"USDScene : Failed to open USD stage : '{fileName}'" ) : IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Write ) + def testAssetPathSlashes ( self ) : + + root = IECoreScene.SceneInterface.create( + os.path.join( os.path.dirname( __file__ ), "data", "assetPathAttribute.usda" ), + IECore.IndexedIO.OpenMode.Read + ) + xform = root.child( "xform" ) + + self.assertEqual( xform.attributeNames(), [ "render:testAsset" ] ) + self.assertNotIn( "\\", xform.readAttribute( "render:testAsset", 0 ).value ) + self.assertTrue( pathlib.Path( xform.readAttribute( "render:testAsset", 0 ).value ).is_file() ) + + @unittest.skipIf( not haveVDB, "No IECoreVDB" ) + def testUsdVolVolumeSlashes( self ) : + + import IECoreVDB + + fileName = os.path.dirname( __file__ ) + "/data/volume.usda" + root = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read ) + child = root.child( "volume" ) + + vdbObject = child.readObject( 0 ) + self.assertNotIn( "\\", vdbObject.fileName() ) + self.assertTrue( pathlib.Path( vdbObject.fileName() ).is_file() ) + if __name__ == "__main__": unittest.main()