diff --git a/Changes b/Changes index b099d11f10..3243da347d 100644 --- a/Changes +++ b/Changes @@ -36,6 +36,30 @@ Breaking Changes - IECoreGL : Removed `PerspectiveCamera.h` header. The implementation was already removed in a Cortex 10.1.0.0 (#1241). - StringAlgo : Removed `join()` (#1221). +10.3.6.0 (relative to 10.3.5.1) +======== + +Improvements +------------ + +- USDScene : Added support for the `doubleSided` attribute. + +10.3.5.1 (relative to 10.3.5.0) +======== + +Fixes +----- + +- USDScene : Fixed compatibility with USD 21.08 (#1259). + +10.3.5.0 (relative to 10.3.4.1) +======== + +Improvements +------------ + +- USDScene : Registered .usdz file format (#1257). + 10.3.4.1 (relative to 10.3.4.0) ======== diff --git a/config/ie/options b/config/ie/options index fc1e692dd9..af0b47cd1f 100644 --- a/config/ie/options +++ b/config/ie/options @@ -324,6 +324,30 @@ if targetApp=="maya" : INSTALL_COREMAYA_POST_COMMAND="scons -i -f config/ie/postCoreMayaInstall MAYA_VERSION='" + mayaVersion + "' INSTALLPREFIX="+appPrefix+" install" WITH_MAYA_PLUGIN_LOADER = 1 + mayaUsdVersion = mayaReg.get( "mayaUsdVersion" ) + mayaUsdReg = IEEnv.registry["apps"]["mayaUsd"].get( mayaUsdVersion, {} ).get( platform ) + # If the Maya usd plugin is not in the registry we build against our standalone USD version + if mayaUsdReg : + pluginUsdVersion = mayaUsdReg["usdVersion"] + # Maya ships the USD libraries with the installation, but not the header files... we use the one that are installed by standalone usd + usdReg = IEEnv.registry["apps"]["usd"].get( pluginUsdVersion, {} ).get( platform ) + if usdReg : + USD_INCLUDE_PATH = os.path.join( usdReg["location"], targetApp, compatibilityVersion, "include" ) + + mayaMajorVersion = mayaVersion.split(".")[0] + mayaLooseVersion = distutils.version.LooseVersion(mayaVersion) + if mayaLooseVersion >= "2022" and mayaLooseVersion < "2023": + # Maya 2022 installs the USD libs and the maya plugin itself for python 2 and 3. This is not the case for the 2020 version + # We make the assumption, that the python version suffix is for Maya 2022 only, because Maya 2023 will be python 3 exclusively. + mayaPythonMajorVersion = mayaReg["pythonVersion"].split(".")[0] + USD_LIB_PATH = os.path.join( mayaUsdReg["location"], mayaMajorVersion, "mayausd/USD{}/lib".format( mayaPythonMajorVersion ) ) + else: + USD_LIB_PATH = os.path.join( mayaUsdReg["location"], mayaMajorVersion, "mayausd/USD/lib" ) + + # Pixar introduced a library prefix `usd_` in USD v21.11, which Autodesk does not use yet, so we have to reset the prefix. + # See https://github.com/Autodesk/maya-usd/issues/2108 for reference + USD_LIB_PREFIX = "" if mayaUsdReg.get( "usdLibPrefix" ) == "" else mayaUsdReg.get( "usdLibPrefix" ) or USD_LIB_PREFIX + # find nuke if we're building for nuke if targetApp=="nuke" : diff --git a/contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp b/contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp index 5e902821dc..d1b7dd250a 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp @@ -56,6 +56,7 @@ IECORE_PUSH_DEFAULT_VISIBILITY #include "pxr/usd/usd/stage.h" #include "pxr/usd/usdGeom/bboxCache.h" #include "pxr/usd/usdGeom/camera.h" +#include "pxr/usd/usdGeom/gprim.h" #include "pxr/usd/usdGeom/metrics.h" #include "pxr/usd/usdGeom/pointInstancer.h" #include "pxr/usd/usdGeom/primvar.h" @@ -796,6 +797,7 @@ namespace const IECore::InternedString g_purposeAttributeName( "usd:purpose" ); const IECore::InternedString g_kindAttributeName( "usd:kind" ); const IECore::InternedString g_lightAttributeName( "light" ); +const IECore::InternedString g_doubleSidedAttributeName( "doubleSided" ); } // namespace @@ -827,6 +829,10 @@ bool USDScene::hasAttribute( const SceneInterface::Name &name ) const return m_location->prim.HasAPI(); } #endif + else if( name == g_doubleSidedAttributeName ) + { + return pxr::UsdGeomGprim( m_location->prim ).GetDoubleSidedAttr().HasAuthoredValue(); + } else if( auto attribute = AttributeAlgo::findUSDAttribute( m_location->prim, name.string() ) ) { return attribute.HasAuthoredValue(); @@ -882,6 +888,11 @@ void USDScene::attributeNames( SceneInterface::NameList &attrs ) const } #endif + if( pxr::UsdGeomGprim( m_location->prim ).GetDoubleSidedAttr().HasAuthoredValue() ) + { + attrs.push_back( g_doubleSidedAttributeName ); + } + std::vector attributes = m_location->prim.GetAuthoredAttributes(); for( const auto &attribute : attributes ) { @@ -973,6 +984,16 @@ ConstObjectPtr USDScene::readAttribute( const SceneInterface::Name &name, double } return new StringData( kind.GetString() ); } + else if( name == g_doubleSidedAttributeName ) + { + pxr::UsdAttribute attr = pxr::UsdGeomGprim( m_location->prim ).GetDoubleSidedAttr(); + bool doubleSided; + if( attr.HasAuthoredValue() && attr.Get( &doubleSided, m_root->getTime( time ) ) ) + { + return new BoolData( doubleSided ); + } + return nullptr; + } else if( pxr::UsdAttribute attribute = AttributeAlgo::findUSDAttribute( m_location->prim, name.string() ) ) { return DataAlgo::fromUSD( attribute, m_root->getTime( time ) ); @@ -1034,6 +1055,28 @@ void USDScene::writeAttribute( const SceneInterface::Name &name, const Object *a } } } + else if( name == g_doubleSidedAttributeName ) + { + if( auto *data = reportedCast( attribute, "USDScene::writeAttribute", name.c_str() ) ) + { + pxr::UsdGeomGprim gprim( m_location->prim ); + if( gprim ) + { + gprim.GetDoubleSidedAttr().Set( data->readable(), m_root->getTime( time ) ); + } + else + { + // We're hamstrung by the fact that USD considers `doubleSided` to be a property + // of a Gprim and not an inheritable attribute as it was in RenderMan and is in Cortex. + // We can't author a Gprim here, because it isn't a concrete type, so we must rely on + // `writeObject()` having been called first to get a suitable concrete type in place. + IECore::msg( + IECore::Msg::Warning, "USDScene::writeAttribute", + boost::format( "Unable to write attribute \"%1%\" to \"%2%\", because it is not a Gprim" ) % name % m_location->prim.GetPath() + ); + } + } + } else if( const IECoreScene::ShaderNetwork *shaderNetwork = runTimeCast( attribute ) ) { m_shaders[name] = shaderNetwork; @@ -1368,6 +1411,13 @@ void USDScene::attributesHash( double time, IECore::MurmurHash &h ) const // Kind can not be animated so no need to update `mightBeTimeVarying`. } + auto doubleSidedAttr = pxr::UsdGeomGprim( m_location->prim ).GetDoubleSidedAttr(); + if( doubleSidedAttr && doubleSidedAttr.HasAuthoredValue() ) + { + haveAttributes = true; + mightBeTimeVarying |= doubleSidedAttr.ValueMightBeTimeVarying(); + } + std::vector attributes = m_location->prim.GetAuthoredAttributes(); for( const auto &attribute : attributes ) { @@ -1456,5 +1506,6 @@ namespace SceneInterface::FileFormatDescription g_descriptionUSD( ".usd", IndexedIO::Read | IndexedIO::Write ); SceneInterface::FileFormatDescription g_descriptionUSDA( ".usda", IndexedIO::Read | IndexedIO::Write ); SceneInterface::FileFormatDescription g_descriptionUSDC( ".usdc", IndexedIO::Read | IndexedIO::Write ); +SceneInterface::FileFormatDescription g_descriptionUSDZ( ".usdz", IndexedIO::Read | IndexedIO::Write ); } // namespace diff --git a/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py b/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py index 6d5d3de58d..1aee65b2bf 100644 --- a/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py +++ b/contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py @@ -3015,5 +3015,85 @@ def testLightAttribute( self ) : } ) ) + def testReadDoubleSidedAttribute( self ) : + + root = IECoreScene.SceneInterface.create( + os.path.join( os.path.dirname( __file__ ), "data", "doubleSidedAttribute.usda" ), + IECore.IndexedIO.OpenMode.Read + ) + + for name, doubleSided in { + "sphere" : None, + "singleSidedSphere" : False, + "doubleSidedSphere" : True + }.items() : + object = root.child( name ) + if doubleSided is None : + self.assertFalse( object.hasAttribute( "doubleSided" ) ) + self.assertNotIn( "doubleSided", object.attributeNames() ) + else : + self.assertTrue( object.hasAttribute( "doubleSided" ) ) + self.assertIn( "doubleSided", object.attributeNames() ) + self.assertEqual( object.readAttribute( "doubleSided", 1 ), IECore.BoolData( doubleSided ) ) + + def testWriteDoubleSidedAttribute( self ) : + + # Write via SceneInterface + + fileName = os.path.join( self.temporaryDirectory(), "doubleSidedAttribute.usda" ) + root = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Write ) + + toWrite = ( + ( "singleSidedSphere", "before", False ), + ( "doubleSidedSphere", "before", True ), + ( "doubleSidedSphereWrittenAfter", "after", True ), + ( "doubleSidedNoObject", "never", True ), + ( "sphere", "before", None ), + ) + + for name, writeObject, doubleSided in toWrite : + + child = root.createChild( name ) + if writeObject == "before" : + child.writeObject( IECoreScene.SpherePrimitive(), 1 ) + + if doubleSided is not None : + + with IECore.CapturingMessageHandler() as mh : + child.writeAttribute( "doubleSided", IECore.BoolData( doubleSided ), 1 ) + + if writeObject != "before" : + self.assertEqual( len( mh.messages ), 1 ) + self.assertEqual( + mh.messages[0].message, + 'Unable to write attribute "doubleSided" to "/{}", because it is not a Gprim'.format( + name + ) + ) + + if writeObject == "after" : + child.writeObject( IECoreScene.SpherePrimitive(), 1 ) + + del root, child + + # Verify via USD API + + stage = pxr.Usd.Stage.Open( fileName ) + + for name, writeObject, doubleSided in toWrite : + + if writeObject != "before" : + doubleSided = None + + if doubleSided is None : + self.assertFalse( + pxr.UsdGeom.Gprim( stage.GetPrimAtPath( "/" + name ) ).GetDoubleSidedAttr().HasAuthoredValue(), + ) + else : + self.assertEqual( + pxr.UsdGeom.Gprim( stage.GetPrimAtPath( "/" + name ) ).GetDoubleSidedAttr().Get( 1 ), + doubleSided + ) + if __name__ == "__main__": unittest.main() diff --git a/contrib/IECoreUSD/test/IECoreUSD/data/doubleSidedAttribute.usda b/contrib/IECoreUSD/test/IECoreUSD/data/doubleSidedAttribute.usda new file mode 100644 index 0000000000..1e5dd4c652 --- /dev/null +++ b/contrib/IECoreUSD/test/IECoreUSD/data/doubleSidedAttribute.usda @@ -0,0 +1,16 @@ +#usda 1.0 + +def Sphere "doubleSidedSphere" +{ + uniform bool doubleSided = 1 +} + +def Sphere "singleSidedSphere" +{ + uniform bool doubleSided = 0 +} + +def Sphere "sphere" +{ +} +