Skip to content

Commit

Permalink
Merge pull request #1400 from johnhaddon/usdNurbs
Browse files Browse the repository at this point in the history
USD CurvesAlgo : Add basic support for reading UsdGeomNurbsCurves
  • Loading branch information
johnhaddon authored Jan 3, 2024
2 parents a9850fd + 285ab04 commit 2d7eb96
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 16 deletions.
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
10.5.x.x (relative to 10.5.4.2)
========

Improvements
------------

- USDScene : Added basic loading of UsdGeomNurbsCurves, converting them to CurvesPrimitives.

10.5.4.2 (relative to 10.5.4.1)
========
Expand Down
69 changes: 53 additions & 16 deletions contrib/IECoreUSD/src/IECoreUSD/CurvesAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

IECORE_PUSH_DEFAULT_VISIBILITY
#include "pxr/usd/usdGeom/basisCurves.h"
#include "pxr/usd/usdGeom/nurbsCurves.h"
IECORE_POP_DEFAULT_VISIBILITY

using namespace IECore;
Expand All @@ -55,13 +56,37 @@ using namespace IECoreUSD;
namespace
{

IECore::ObjectPtr readCurves( pxr::UsdGeomBasisCurves &curves, pxr::UsdTimeCode time, const Canceller *canceller )
IECore::ObjectPtr readCurves( pxr::UsdGeomCurves &curves, pxr::UsdTimeCode time, const IECore::CubicBasisf &basis, bool periodic, const Canceller *canceller )
{
Canceller::check( canceller );
pxr::VtIntArray vertexCountsArray;
curves.GetCurveVertexCountsAttr().Get( &vertexCountsArray, time );
IECore::IntVectorDataPtr countData = DataAlgo::fromUSD( vertexCountsArray );

Canceller::check( canceller );
IECoreScene::CurvesPrimitivePtr newCurves = new IECoreScene::CurvesPrimitive( countData, basis, periodic );
PrimitiveAlgo::readPrimitiveVariables( curves, time, newCurves.get(), canceller );

Canceller::check( canceller );
PrimitiveAlgo::readPrimitiveVariable(
curves.GetWidthsAttr(), time, newCurves.get(), "width", PrimitiveAlgo::fromUSD( curves.GetWidthsInterpolation() )
);

return newCurves;
}

bool curvesMightBeTimeVarying( pxr::UsdGeomCurves &curves )
{
return
curves.GetCurveVertexCountsAttr().ValueMightBeTimeVarying() ||
curves.GetWidthsAttr().ValueMightBeTimeVarying() ||
PrimitiveAlgo::primitiveVariablesMightBeTimeVarying( curves )
;
}

IECore::ObjectPtr readBasisCurves( pxr::UsdGeomBasisCurves &curves, pxr::UsdTimeCode time, const Canceller *canceller )
{

// Basis
Canceller::check( canceller );
IECore::CubicBasisf basis = CubicBasisf::linear();
Expand Down Expand Up @@ -103,32 +128,44 @@ IECore::ObjectPtr readCurves( pxr::UsdGeomBasisCurves &curves, pxr::UsdTimeCode
IECore::msg( IECore::Msg::Warning, "USDScene", boost::format( "Unsupported wrap \"%1%\"" ) % wrap );
}

// Curves and primvars
return readCurves( curves, time, basis, periodic, canceller );
}

IECoreScene::CurvesPrimitivePtr newCurves = new IECoreScene::CurvesPrimitive( countData, basis, periodic );
PrimitiveAlgo::readPrimitiveVariables( curves, time, newCurves.get(), canceller );
bool basisCurvesMightBeTimeVarying( pxr::UsdGeomBasisCurves &curves )
{
return
curvesMightBeTimeVarying( curves ) ||
curves.GetTypeAttr().ValueMightBeTimeVarying() ||
curves.GetBasisAttr().ValueMightBeTimeVarying() ||
curves.GetWrapAttr().ValueMightBeTimeVarying()
;
}

IECore::ObjectPtr readNurbsCurves( pxr::UsdGeomNurbsCurves &curves, pxr::UsdTimeCode time, const Canceller *canceller )
{
IECore::CubicBasisf basis = IECore::CubicBasisf::linear();

Canceller::check( canceller );
PrimitiveAlgo::readPrimitiveVariable(
curves.GetWidthsAttr(), time, newCurves.get(), "width", PrimitiveAlgo::fromUSD( curves.GetWidthsInterpolation() )
);
pxr::VtIntArray order;
curves.GetOrderAttr().Get( &order, time );
if( std::all_of( order.begin(), order.end(), [] ( int o ) { return o == 4; } ) )
{
basis = CubicBasisf::bSpline();
}

return newCurves;
return readCurves( curves, time, basis, false, canceller );
}

bool curvesMightBeTimeVarying( pxr::UsdGeomBasisCurves &curves )
bool nurbsCurvesMightBeTimeVarying( pxr::UsdGeomNurbsCurves &curves )
{
return
curves.GetCurveVertexCountsAttr().ValueMightBeTimeVarying() ||
curves.GetTypeAttr().ValueMightBeTimeVarying() ||
curves.GetBasisAttr().ValueMightBeTimeVarying() ||
curves.GetWrapAttr().ValueMightBeTimeVarying() ||
curves.GetWidthsAttr().ValueMightBeTimeVarying() ||
PrimitiveAlgo::primitiveVariablesMightBeTimeVarying( curves )
curvesMightBeTimeVarying( curves ) ||
curves.GetOrderAttr().ValueMightBeTimeVarying()
;
}

ObjectAlgo::ReaderDescription<pxr::UsdGeomBasisCurves> g_curvesReaderDescription( pxr::TfToken( "BasisCurves" ), readCurves, curvesMightBeTimeVarying );
ObjectAlgo::ReaderDescription<pxr::UsdGeomBasisCurves> g_curvesReaderDescription( pxr::TfToken( "BasisCurves" ), readBasisCurves, basisCurvesMightBeTimeVarying );
ObjectAlgo::ReaderDescription<pxr::UsdGeomNurbsCurves> g_nurbsCurvesReaderDescription( pxr::TfToken( "NurbsCurves" ), readNurbsCurves, nurbsCurvesMightBeTimeVarying );

} // namespace

Expand Down
52 changes: 52 additions & 0 deletions contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,58 @@ def testCurveBasisAndWrap( self ) :
self.assertEqual( curves2, curves )
del root

def testReadNurbsCurves( self ) :

# Write USD file

fileName = os.path.join( self.temporaryDirectory(), "nurbs.usda" )
stage = pxr.Usd.Stage.CreateNew( fileName )

curves = pxr.UsdGeom.NurbsCurves.Define( stage, "/cubic" )
curves.CreateCurveVertexCountsAttr().Set( [ 4 ] )
curves.CreatePointsAttr().Set( [ ( x, x, x ) for x in range( 0, 4 ) ] )
curves.CreateOrderAttr().Set( [ 4 ] )
curves.CreateKnotsAttr().Set( [ 0, 0, 0, 0.333, 0.666, 1, 1, 1 ] )

curves = pxr.UsdGeom.NurbsCurves.Define( stage, "/nonCubic" )
curves.CreateCurveVertexCountsAttr().Set( [ 4 ] )
curves.CreatePointsAttr().Set( [ ( x, x, x ) for x in range( 0, 4 ) ] )
curves.CreateOrderAttr().Set( [ 3 ] )
curves.CreateKnotsAttr().Set( [ 0, 0, 0, 0.5, 1, 1, 1 ] )

stage.GetRootLayer().Save()
del stage

# Load and check

root = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read )

cubic = root.child( "cubic" ).readObject( 0.0 )
self.assertIsInstance( cubic, IECoreScene.CurvesPrimitive )
self.assertEqual( cubic.verticesPerCurve(), IECore.IntVectorData( [ 4 ] ) )
self.assertEqual( cubic.basis(), IECore.CubicBasisf.bSpline() )
self.assertEqual( cubic.periodic(), False )
self.assertEqual(
cubic["P"].data,
IECore.V3fVectorData(
[ imath.V3f( x ) for x in range( 0, 4 ) ],
IECore.GeometricData.Interpretation.Point
)
)

nonCubic = root.child( "nonCubic" ).readObject( 0.0 )
self.assertIsInstance( nonCubic, IECoreScene.CurvesPrimitive )
self.assertEqual( nonCubic.verticesPerCurve(), IECore.IntVectorData( [ 4 ] ) )
self.assertEqual( nonCubic.basis(), IECore.CubicBasisf.linear() )
self.assertEqual( nonCubic.periodic(), False )
self.assertEqual(
cubic["P"].data,
IECore.V3fVectorData(
[ imath.V3f( x ) for x in range( 0, 4 ) ],
IECore.GeometricData.Interpretation.Point
)
)

def testIndexedWidths( self ) :

# Write USD file from points with indexed widths
Expand Down

0 comments on commit 2d7eb96

Please sign in to comment.