Skip to content

Commit c470491

Browse files
committed
GeometryAlgo : Export subdivision tags
And add support for loop subdivs.
1 parent d2888a7 commit c470491

File tree

2 files changed

+284
-2
lines changed

2 files changed

+284
-2
lines changed

python/IECoreRenderManTest/RendererTest.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import IECore
4646
import IECoreImage
4747
import IECoreScene
48+
import IECoreRenderManTest
4849

4950
import GafferTest
5051
import GafferScene
@@ -825,6 +826,185 @@ def testConnectionToOSLShader( self ) :
825826
image = OpenImageIO.ImageBuf( fileName )
826827
self.assertEqual( image.getpixel( 320, 240, 0 ), ( 1.0, 1.0, 0.0, 1.0 ) )
827828

829+
def testSubdivInterpolatedBoundary( self ) :
830+
831+
for interpolateBoundary, expected in [
832+
( IECoreScene.MeshPrimitive.interpolateBoundaryNone, 0 ),
833+
( IECoreScene.MeshPrimitive.interpolateBoundaryEdgeAndCorner, 1 ),
834+
( IECoreScene.MeshPrimitive.interpolateBoundaryEdgeOnly, 2 ),
835+
] :
836+
837+
with self.subTest( interpolateBoundary = interpolateBoundary ) :
838+
839+
with IECoreRenderManTest.RileyCapture() as capture :
840+
841+
renderer = GafferScene.Private.IECoreScenePreview.Renderer.create(
842+
"RenderMan",
843+
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
844+
)
845+
846+
mesh = IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( -1 ), imath.V2f( 1 ) ) )
847+
mesh.setInterpolation( "catmullClark" )
848+
mesh.setInterpolateBoundary( interpolateBoundary )
849+
850+
renderer.object(
851+
"mesh", mesh, renderer.attributes( IECore.CompoundObject() )
852+
)
853+
854+
del mesh, renderer
855+
856+
proto = next(
857+
x for x in capture.json if x["method"] == "CreateGeometryPrototype"
858+
)
859+
self.__assertInTags(
860+
proto, "interpolateboundary", intArgs = [ expected ]
861+
)
862+
863+
def testSubdivFaceVaryingLinearInterpolation( self ) :
864+
865+
for faceVaryingLinearInterpolation, expected in [
866+
( IECoreScene.MeshPrimitive.faceVaryingLinearInterpolationNone, 2 ),
867+
( IECoreScene.MeshPrimitive.faceVaryingLinearInterpolationCornersOnly, 1 ),
868+
( IECoreScene.MeshPrimitive.faceVaryingLinearInterpolationCornersPlus1, 1 ),
869+
( IECoreScene.MeshPrimitive.faceVaryingLinearInterpolationCornersPlus2, 1 ),
870+
( IECoreScene.MeshPrimitive.faceVaryingLinearInterpolationBoundaries, 3 ),
871+
( IECoreScene.MeshPrimitive.faceVaryingLinearInterpolationAll, 0 ),
872+
] :
873+
874+
with self.subTest( faceVaryingLinearInterpolation = faceVaryingLinearInterpolation ) :
875+
876+
with IECoreRenderManTest.RileyCapture() as capture :
877+
878+
renderer = GafferScene.Private.IECoreScenePreview.Renderer.create(
879+
"RenderMan",
880+
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
881+
)
882+
883+
mesh = IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( -1 ), imath.V2f( 1 ) ) )
884+
mesh.setInterpolation( "catmullClark" )
885+
mesh.setFaceVaryingLinearInterpolation( faceVaryingLinearInterpolation )
886+
887+
renderer.object(
888+
"mesh", mesh, renderer.attributes( IECore.CompoundObject() )
889+
)
890+
891+
del mesh, renderer
892+
893+
proto = next(
894+
x for x in capture.json if x["method"] == "CreateGeometryPrototype"
895+
)
896+
self.__assertInTags(
897+
proto, "facevaryinginterpolateboundary", intArgs = [ expected ]
898+
)
899+
900+
def testSubdivTriangleSubdivisionRule( self ) :
901+
902+
for rule, expected in [
903+
( IECoreScene.MeshPrimitive.triangleSubdivisionRuleCatmullClark, 0 ),
904+
( IECoreScene.MeshPrimitive.triangleSubdivisionRuleSmooth, 2 ),
905+
] :
906+
907+
with self.subTest( rule = rule ) :
908+
909+
with IECoreRenderManTest.RileyCapture() as capture :
910+
911+
renderer = GafferScene.Private.IECoreScenePreview.Renderer.create(
912+
"RenderMan",
913+
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
914+
)
915+
916+
mesh = IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( -1 ), imath.V2f( 1 ) ) )
917+
mesh.setInterpolation( "catmullClark" )
918+
mesh.setTriangleSubdivisionRule( rule )
919+
920+
renderer.object(
921+
"mesh", mesh, renderer.attributes( IECore.CompoundObject() )
922+
)
923+
924+
del mesh, renderer
925+
926+
proto = next(
927+
x for x in capture.json if x["method"] == "CreateGeometryPrototype"
928+
)
929+
self.__assertInTags(
930+
proto, "smoothtriangles", intArgs = [ expected ]
931+
)
932+
933+
def testSubdivisionScheme( self ) :
934+
935+
for interpolation, scheme in [
936+
( IECoreScene.MeshPrimitive.interpolationLinear, None ),
937+
( IECoreScene.MeshPrimitive.interpolationCatmullClark, "catmull-clark" ),
938+
( IECoreScene.MeshPrimitive.interpolationLoop, "loop" ),
939+
] :
940+
941+
with self.subTest( interpolation = interpolation ) :
942+
943+
with IECoreRenderManTest.RileyCapture() as capture :
944+
945+
renderer = GafferScene.Private.IECoreScenePreview.Renderer.create(
946+
"RenderMan",
947+
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
948+
)
949+
950+
mesh = IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( -1 ), imath.V2f( 1 ) ) )
951+
mesh.setInterpolation( interpolation )
952+
953+
renderer.object(
954+
"mesh", mesh, renderer.attributes( IECore.CompoundObject() )
955+
)
956+
957+
del mesh, renderer
958+
959+
proto = next(
960+
x for x in capture.json if x["method"] == "CreateGeometryPrototype"
961+
)
962+
963+
if scheme is not None :
964+
self.assertEqual( proto["type"], "Ri:SubdivisionMesh" )
965+
self.__assertPrimitiveVariableEqual( proto, "Ri:scheme", [ scheme ] )
966+
else :
967+
self.__assertNotInPrimitiveVariables( proto, "Ri:scheme" )
968+
self.assertEqual( proto["type"], "Ri:PolygonMesh" )
969+
970+
def __assertPrimitiveVariableEqual( self, geometryPrototype, name, data ) :
971+
972+
p = next( x for x in geometryPrototype["primvars"]["params"] if x["info"]["name"] == name )
973+
self.assertEqual( p["data"], data )
974+
975+
def __assertNotInPrimitiveVariables( self, geometryPrototype, name ) :
976+
977+
self.assertNotIn(
978+
name, { x["info"]["name"] for x in geometryPrototype["primvars"]["params"] }
979+
)
980+
981+
def __assertInTags( self, geometryPrototype, tag, intArgs = [], floatArgs = [] ) :
982+
983+
tags = next( x for x in geometryPrototype["primvars"]["params"] if x["info"]["name"] == "Ri:subdivtags" )["data"]
984+
numArgs = next( x for x in geometryPrototype["primvars"]["params"] if x["info"]["name"] == "Ri:subdivtagnargs" )["data"]
985+
ints = next( x for x in geometryPrototype["primvars"]["params"] if x["info"]["name"] == "Ri:subdivtagintargs" )["data"]
986+
floats = next( x for x in geometryPrototype["primvars"]["params"] if x["info"]["name"] == "Ri:subdivtagfloatargs" )["data"]
987+
988+
foundTag = False
989+
for t in tags :
990+
991+
if t == tag :
992+
self.assertEqual( numArgs[0:3], [ len( intArgs ), len( floatArgs ), 0 ] )
993+
self.assertEqual( ints[0:len(intArgs)], intArgs )
994+
self.assertEqual( floats[0:len(floatArgs)], floatArgs )
995+
foundTag = True
996+
997+
# Move to next tag
998+
del ints[0:numArgs[0]]
999+
del floats[0:numArgs[1]]
1000+
del numArgs[0:3]
1001+
1002+
self.assertEqual( len( numArgs ), 0 )
1003+
self.assertEqual( len( ints ), 0 )
1004+
self.assertEqual( len( floats ), 0 )
1005+
1006+
self.assertTrue( foundTag )
1007+
8281008
def __colorAtUV( self, image, uv ) :
8291009

8301010
dimensions = image.dataWindow.size() + imath.V2i( 1 )

src/IECoreRenderMan/GeometryAlgo.cpp

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,76 @@ GeometryAlgo::ConverterDescription<SpherePrimitive> g_sphereConverterDescription
413413
namespace
414414
{
415415

416+
int interpolateBoundary( const IECoreScene::MeshPrimitive *mesh )
417+
{
418+
const InternedString s = mesh->getInterpolateBoundary();
419+
if( s == IECoreScene::MeshPrimitive::interpolateBoundaryNone )
420+
{
421+
return 0;
422+
}
423+
else if( s == IECoreScene::MeshPrimitive::interpolateBoundaryEdgeAndCorner )
424+
{
425+
return 1;
426+
}
427+
else if( s == IECoreScene::MeshPrimitive::interpolateBoundaryEdgeOnly )
428+
{
429+
return 2;
430+
}
431+
else
432+
{
433+
msg( Msg::Error, "GeometryAlgo", fmt::format( "Unknown boundary interpolation \"{}\"", s.string() ) );
434+
return 0;
435+
}
436+
}
437+
438+
int faceVaryingInterpolateBoundary( const IECoreScene::MeshPrimitive *mesh )
439+
{
440+
const InternedString s = mesh->getFaceVaryingLinearInterpolation();
441+
if( s == IECoreScene::MeshPrimitive::faceVaryingLinearInterpolationNone )
442+
{
443+
return 2;
444+
}
445+
else if(
446+
s == IECoreScene::MeshPrimitive::faceVaryingLinearInterpolationCornersOnly ||
447+
s == IECoreScene::MeshPrimitive::faceVaryingLinearInterpolationCornersPlus1 ||
448+
s == IECoreScene::MeshPrimitive::faceVaryingLinearInterpolationCornersPlus2
449+
)
450+
{
451+
return 1;
452+
}
453+
else if( s == IECoreScene::MeshPrimitive::faceVaryingLinearInterpolationBoundaries )
454+
{
455+
return 3;
456+
}
457+
else if( s == IECoreScene::MeshPrimitive::faceVaryingLinearInterpolationAll )
458+
{
459+
return 0;
460+
}
461+
else
462+
{
463+
msg( Msg::Error, "GeometryAlgo", fmt::format( "Unknown facevarying linear interpolation \"{}\"", s.string() ) );
464+
return 0;
465+
}
466+
}
467+
468+
int smoothTriangles( const IECoreScene::MeshPrimitive *mesh )
469+
{
470+
const InternedString s = mesh->getTriangleSubdivisionRule();
471+
if( s == IECoreScene::MeshPrimitive::triangleSubdivisionRuleCatmullClark )
472+
{
473+
return 0;
474+
}
475+
else if( s == IECoreScene::MeshPrimitive::triangleSubdivisionRuleSmooth )
476+
{
477+
return 2;
478+
}
479+
else
480+
{
481+
msg( Msg::Error, "GeometryAlgo", fmt::format( "Unknown triangle subdivision rule \"{}\"", s.string() ) );
482+
return 0;
483+
}
484+
}
485+
416486
riley::GeometryPrototypeId convertStaticMesh( const IECoreScene::MeshPrimitive *mesh, riley::Riley *riley )
417487
{
418488
RtPrimVarList primVars(
@@ -432,17 +502,31 @@ riley::GeometryPrototypeId convertStaticMesh( const IECoreScene::MeshPrimitive *
432502
primVars.SetIntegerDetail( Rix::k_Ri_vertices, mesh->vertexIds()->readable().data(), RtDetailType::k_facevarying );
433503

434504
RtUString geometryType = Rix::k_Ri_PolygonMesh;
435-
if( mesh->interpolation() == "catmullClark" )
505+
if( mesh->interpolation() != MeshPrimitive::interpolationLinear.string() )
436506
{
437507
geometryType = Rix::k_Ri_SubdivisionMesh;
438-
primVars.SetString( Rix::k_Ri_scheme, Rix::k_catmullclark );
508+
if( mesh->interpolation() == MeshPrimitive::interpolationCatmullClark.string() )
509+
{
510+
primVars.SetString( Rix::k_Ri_scheme, Rix::k_catmullclark );
511+
}
512+
else if( mesh->interpolation() == MeshPrimitive::interpolationLoop.string() )
513+
{
514+
primVars.SetString( Rix::k_Ri_scheme, Rix::k_loop );
515+
}
516+
else
517+
{
518+
msg( Msg::Error, "GeometryAlgo", fmt::format( "Unknown mesh interpolation \"{}\"", mesh->interpolation() ) );
519+
primVars.SetString( Rix::k_Ri_scheme, Rix::k_catmullclark );
520+
}
439521

440522
vector<RtUString> tagNames;
441523
vector<RtInt> tagArgCounts;
442524
vector<RtInt> tagIntArgs;
443525
vector<RtFloat> tagFloatArgs;
444526
vector<RtToken> tagStringArgs;
445527

528+
// Creases
529+
446530
for( int creaseLength : mesh->creaseLengths()->readable() )
447531
{
448532
tagNames.push_back( Rix::k_crease );
@@ -454,6 +538,8 @@ riley::GeometryPrototypeId convertStaticMesh( const IECoreScene::MeshPrimitive *
454538
tagIntArgs = mesh->creaseIds()->readable();
455539
tagFloatArgs = mesh->creaseSharpnesses()->readable();
456540

541+
// Corners
542+
457543
if( mesh->cornerIds()->readable().size() )
458544
{
459545
tagNames.push_back( Rix::k_corner );
@@ -464,6 +550,22 @@ riley::GeometryPrototypeId convertStaticMesh( const IECoreScene::MeshPrimitive *
464550
tagFloatArgs.insert( tagFloatArgs.end(), mesh->cornerSharpnesses()->readable().begin(), mesh->cornerSharpnesses()->readable().end() );
465551
}
466552

553+
// Interpolation rules
554+
555+
tagNames.push_back( Rix::k_interpolateboundary );
556+
tagArgCounts.insert( tagArgCounts.end(), { 1, 0, 0 } );
557+
tagIntArgs.push_back( interpolateBoundary( mesh ) );
558+
559+
tagNames.push_back( Rix::k_facevaryinginterpolateboundary );
560+
tagArgCounts.insert( tagArgCounts.end(), { 1, 0, 0 } );
561+
tagIntArgs.push_back( faceVaryingInterpolateBoundary( mesh ) );
562+
563+
tagNames.push_back( Rix::k_smoothtriangles );
564+
tagArgCounts.insert( tagArgCounts.end(), { 1, 0, 0 } );
565+
tagIntArgs.push_back( smoothTriangles( mesh ) );
566+
567+
// Pseudo-primvars to hold the tags
568+
467569
primVars.SetStringArray( Rix::k_Ri_subdivtags, tagNames.data(), tagNames.size() );
468570
primVars.SetIntegerArray( Rix::k_Ri_subdivtagnargs, tagArgCounts.data(), tagArgCounts.size() );
469571
primVars.SetFloatArray( Rix::k_Ri_subdivtagfloatargs, tagFloatArgs.data(), tagFloatArgs.size() );

0 commit comments

Comments
 (0)