Skip to content

Commit a747d80

Browse files
Merge pull request #6840 from GafferHQ/renderManDeformationBlur
RenderMan GeometryAlgo : Omit animation on everything except "P"
2 parents 0e3e588 + 860bfd7 commit a747d80

File tree

8 files changed

+216
-98
lines changed

8 files changed

+216
-98
lines changed

Changes.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
Fixes
55
-----
66

7+
- RenderMan :
8+
- Fixed crashes rendering deformation motion blur.
9+
- Stopped exporting animation for primitive variables other than "P". RenderMan doesn't support animation on any other primitive variable.
10+
- Added the name of the relevant primitive variable to warnings about unsupported data types.
711
- SConstruct, ShowURL, ArnoldtextureBake : Replaced deprecated distutils with modern alternatives.
812

9-
1013
1.6.14.0 (relative to 1.6.13.0)
1114
========
1215

python/IECoreRenderManTest/RendererTest.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,113 @@ def testTransformMotionBlur( self ) :
15431543
del object
15441544
del renderer
15451545

1546+
def testDeformationMotionBlur( self ) :
1547+
1548+
renderer = GafferScene.Private.IECoreScenePreview.Renderer.create(
1549+
self.renderer,
1550+
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
1551+
)
1552+
1553+
# RenderMan needs the shutter upfront when the Riley object is created,
1554+
# so until we can come up with something, the renderer client is responsible
1555+
# for passing the shutter separately from the camera.
1556+
renderer.option( "ri:Ri:Shutter", IECore.V2fData( imath.V2f( 0, 1 ) ) )
1557+
1558+
renderer.output(
1559+
"test",
1560+
IECoreScene.Output(
1561+
"test",
1562+
"ieDisplay",
1563+
"rgba",
1564+
{
1565+
"driverType" : "ImageDisplayDriver",
1566+
"handle" : "deformationMotion",
1567+
}
1568+
)
1569+
)
1570+
1571+
staticMesh = IECoreScene.MeshPrimitive.createSphere( 1 )
1572+
meshes = []
1573+
for x in [ -3, 3 ] :
1574+
mesh = staticMesh.copy()
1575+
for i in range( len( mesh["P"].data ) ) :
1576+
mesh["P"].data[i] += imath.V3f( x, 0, -3 )
1577+
meshes.append( mesh )
1578+
1579+
object = renderer.object(
1580+
"sphere", meshes, [ 0, 1 ],
1581+
renderer.attributes( IECore.CompoundObject() )
1582+
)
1583+
1584+
renderer.render()
1585+
1586+
image = IECoreImage.ImageDisplayDriver.storedImage( "deformationMotion" )
1587+
1588+
for i in range( 0, 10 ) :
1589+
u = i / 9.0
1590+
self.assertEqual( self.__colorAtUV( image, imath.V2f( u, 0.1 ) ).a, 0 )
1591+
self.assertGreaterEqual( self.__colorAtUV( image, imath.V2f( u, 0.5 ) ).a, 0.1 )
1592+
self.assertEqual( self.__colorAtUV( image, imath.V2f( u, 0.9 ) ).a, 0 )
1593+
1594+
del object
1595+
del renderer
1596+
1597+
def testDeformationOnlyIncludesPosition( self ) :
1598+
1599+
with IECoreRenderManTest.RileyCapture() as capture :
1600+
1601+
renderer = GafferScene.Private.IECoreScenePreview.Renderer.create(
1602+
self.renderer,
1603+
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
1604+
)
1605+
1606+
renderer.option( "ri:Ri:Shutter", IECore.V2fData( imath.V2f( 0, 1 ) ) )
1607+
1608+
staticMesh = IECoreScene.MeshPrimitive.createSphere( 1 )
1609+
meshes = []
1610+
for x in [ 0, 1 ] :
1611+
mesh = staticMesh.copy()
1612+
for i in range( len( mesh["P"].data ) ) :
1613+
mesh["P"].data[i] += imath.V3f( x, 0, 0 )
1614+
mesh["staticPoint"] = staticMesh["P"]
1615+
mesh["animatedPoint"] = mesh["P"]
1616+
mesh["staticFloat"] = IECoreScene.PrimitiveVariable(
1617+
IECoreScene.PrimitiveVariable.Interpolation.Constant,
1618+
IECore.FloatData( 1 )
1619+
)
1620+
mesh["animatedFloat"] = IECoreScene.PrimitiveVariable(
1621+
IECoreScene.PrimitiveVariable.Interpolation.Constant,
1622+
IECore.FloatData( x )
1623+
)
1624+
meshes.append( mesh )
1625+
1626+
object = renderer.object(
1627+
"sphere", meshes, [ 0, 1 ],
1628+
renderer.attributes( IECore.CompoundObject() )
1629+
)
1630+
1631+
del object
1632+
del renderer
1633+
1634+
prototype = next(
1635+
x for x in capture.json if x["method"] == "CreateGeometryPrototype"
1636+
)
1637+
primVars = prototype["primvars"]
1638+
self.assertEqual( primVars["times"], [ 0, 1 ] )
1639+
1640+
for name, expectedMotion in {
1641+
"P" : True,
1642+
"staticPoint" : False,
1643+
"animatedPoint" : False,
1644+
"staticFloat" : False,
1645+
"animatedFloat" : False,
1646+
}.items() :
1647+
1648+
with self.subTest( name = name ) :
1649+
1650+
param = next( x for x in primVars["params"] if x["info"]["name"] == name )
1651+
self.assertEqual( param["info"]["motion"], expectedMotion )
1652+
15461653
def testUnknownCommands( self ) :
15471654

15481655
messageHandler = IECore.CapturingMessageHandler()

src/IECoreRenderMan/CurvesAlgo.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ namespace
4848

4949
void convertCurvesTopology( const IECoreScene::CurvesPrimitive *curves, RtPrimVarList &primVars, const std::string &messageContext )
5050
{
51-
primVars.SetDetail(
52-
curves->variableSize( PrimitiveVariable::Uniform ),
53-
curves->variableSize( PrimitiveVariable::Vertex ),
54-
curves->variableSize( PrimitiveVariable::Varying ),
55-
curves->variableSize( PrimitiveVariable::FaceVarying )
56-
);
57-
5851
if( curves->basis().standardBasis() == StandardCubicBasis::Unknown )
5952
{
6053
IECore::msg( IECore::Msg::Warning, messageContext, "Unsupported CubicBasis" );
@@ -90,15 +83,15 @@ void convertCurvesTopology( const IECoreScene::CurvesPrimitive *curves, RtPrimVa
9083

9184
RtUString convertStaticCurves( const IECoreScene::CurvesPrimitive *curves, RtPrimVarList &primVars, const std::string &messageContext )
9285
{
86+
GeometryAlgo::convertPrimitive( curves, primVars, messageContext );
9387
convertCurvesTopology( curves, primVars, messageContext );
94-
GeometryAlgo::convertPrimitiveVariables( curves, primVars, messageContext );
9588
return Loader::strings().k_Ri_Curves;
9689
}
9790

9891
RtUString convertAnimatedCurves( const std::vector<const IECoreScene::CurvesPrimitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVars, const std::string &messageContext )
9992
{
93+
GeometryAlgo::convertPrimitive( reinterpret_cast<const std::vector<const IECoreScene::Primitive *> &>( samples ), sampleTimes, primVars, messageContext );
10094
convertCurvesTopology( samples[0], primVars, messageContext );
101-
GeometryAlgo::convertPrimitiveVariables( reinterpret_cast<const std::vector<const IECoreScene::Primitive *> &>( samples ), sampleTimes, primVars, messageContext );
10295
return Loader::strings().k_Ri_Curves;
10396
}
10497

src/IECoreRenderMan/GeometryAlgo.cpp

Lines changed: 92 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
#include "GeometryAlgo.h"
3636

37+
#include "Loader.h"
3738
#include "ParamListAlgo.h"
3839

3940
#include "IECore/DataAlgo.h"
@@ -273,7 +274,7 @@ struct PrimitiveVariableConverter
273274
IECore::msg(
274275
IECore::Msg::Warning,
275276
m_messageContext,
276-
fmt::format( "Unsupported primitive variable of type \"{}\"", data->typeName() )
277+
fmt::format( "Unsupported primitive variable \"{}\" of type \"{}\"", name.CStr(), data->typeName() )
277278
);
278279
}
279280

@@ -311,6 +312,83 @@ struct PrimitiveVariableConverter
311312

312313
};
313314

315+
void convertDetail( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList )
316+
{
317+
primVarList.SetDetail(
318+
primitive->variableSize( PrimitiveVariable::Uniform ),
319+
primitive->variableSize( PrimitiveVariable::Vertex ),
320+
primitive->variableSize( PrimitiveVariable::Varying ),
321+
primitive->variableSize( PrimitiveVariable::FaceVarying )
322+
);
323+
}
324+
325+
const std::string g_p( "P" );
326+
327+
void convertP( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList, const std::string &messageContext )
328+
{
329+
auto it = primitive->variables.find( g_p );
330+
if( it != primitive->variables.end() )
331+
{
332+
const PrimitiveVariableConverter converter( messageContext );
333+
dispatch( it->second.data.get(), converter, Loader::strings().k_P, it->second, primVarList );
334+
}
335+
}
336+
337+
void convertP( const std::vector<const IECoreScene::Primitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVarList, const std::string &messageContext )
338+
{
339+
const auto firstSampleIt = samples[0]->variables.find( g_p );
340+
if( firstSampleIt == samples[0]->variables.end() )
341+
{
342+
return;
343+
}
344+
345+
bool animated = false;
346+
for( size_t i = 1; i < samples.size(); ++i )
347+
{
348+
auto it = samples[i]->variables.find( g_p );
349+
if( it == samples[i]->variables.end() )
350+
{
351+
animated = false;
352+
break;
353+
}
354+
else if( it->second != firstSampleIt->second )
355+
{
356+
animated = true;
357+
}
358+
}
359+
360+
const PrimitiveVariableConverter converter( messageContext );
361+
if( animated )
362+
{
363+
primVarList.SetTimes( sampleTimes.size(), sampleTimes.data() );
364+
for( size_t i = 0; i < samples.size(); ++i )
365+
{
366+
auto it = samples[i]->variables.find( g_p );
367+
assert( it != samples[i]->variables.end() );
368+
dispatch( it->second.data.get(), converter, Loader::strings().k_P, it->second, primVarList, i );
369+
}
370+
}
371+
else
372+
{
373+
dispatch( firstSampleIt->second.data.get(), converter, Loader::strings().k_P, firstSampleIt->second, primVarList );
374+
}
375+
}
376+
377+
void convertPrimitiveVariables( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList, const std::string &messageContext )
378+
{
379+
const PrimitiveVariableConverter converter( messageContext );
380+
for( const auto &[name, primitiveVariable] : primitive->variables )
381+
{
382+
if( name == g_p )
383+
{
384+
// Dealt with in `convertP()`
385+
continue;
386+
}
387+
const RtUString convertedName( name == "uv" ? "st" : name.c_str() );
388+
dispatch( primitiveVariable.data.get(), converter, convertedName, primitiveVariable, primVarList );
389+
}
390+
}
391+
314392
} // namespace
315393

316394
//////////////////////////////////////////////////////////////////////////
@@ -351,57 +429,21 @@ void IECoreRenderMan::GeometryAlgo::registerConverter( IECore::TypeId fromType,
351429
registry()[fromType] = { converter, motionConverter };
352430
}
353431

354-
void IECoreRenderMan::GeometryAlgo::convertPrimitiveVariables( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList, const std::string &messageContext )
432+
void IECoreRenderMan::GeometryAlgo::convertPrimitive( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList, const std::string &messageContext )
355433
{
356-
const PrimitiveVariableConverter converter( messageContext );
357-
for( const auto &[name, primitiveVariable] : primitive->variables )
358-
{
359-
const RtUString convertedName( name == "uv" ? "st" : name.c_str() );
360-
dispatch( primitiveVariable.data.get(), converter, convertedName, primitiveVariable, primVarList );
361-
}
434+
convertDetail( primitive, primVarList );
435+
convertP( primitive, primVarList, messageContext );
436+
convertPrimitiveVariables( primitive, primVarList, messageContext );
362437
}
363438

364-
void IECoreRenderMan::GeometryAlgo::convertPrimitiveVariables( const std::vector<const IECoreScene::Primitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVarList, const std::string &messageContext )
439+
void IECoreRenderMan::GeometryAlgo::convertPrimitive( const std::vector<const IECoreScene::Primitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVarList, const std::string &messageContext = "GeometryAlgo::convertPrimitive" )
365440
{
366-
const PrimitiveVariableConverter converter( messageContext );
367-
368-
bool haveSetTimes = false;
369-
for( const auto &[name, primitiveVariable] : samples[0]->variables )
370-
{
371-
bool animated = false;
372-
for( size_t i = 1; i < samples.size(); ++i )
373-
{
374-
auto it = samples[i]->variables.find( name );
375-
if( it == samples[i]->variables.end() )
376-
{
377-
animated = false;
378-
break;
379-
}
380-
else if( it->second != primitiveVariable )
381-
{
382-
animated = true;
383-
}
384-
}
385-
386-
const RtUString convertedName( name == "uv" ? "st" : name.c_str() );
387-
if( animated )
388-
{
389-
if( !haveSetTimes )
390-
{
391-
primVarList.SetTimes( sampleTimes.size(), sampleTimes.data() );
392-
haveSetTimes = true;
393-
}
394-
395-
for( size_t i = 0; i < samples.size(); ++i )
396-
{
397-
auto it = samples[i]->variables.find( name );
398-
assert( it != samples[i]->variables.end() );
399-
dispatch( it->second.data.get(), converter, convertedName, primitiveVariable, primVarList, i );
400-
}
401-
}
402-
else
403-
{
404-
dispatch( primitiveVariable.data.get(), converter, convertedName, primitiveVariable, primVarList );
405-
}
406-
}
441+
convertDetail( samples[0], primVarList );
442+
// "P" is the only primitive variable that RenderMan allows to be animated
443+
// so we deal with it separately. When it is animated, `convertP()` will
444+
// call `primVarList.SetTimes()` appropriately. It seems we need to call
445+
// this before adding any primitive variables, animated or not, or we get
446+
// crashes in RenderMan.
447+
convertP( samples, sampleTimes, primVarList, messageContext );
448+
convertPrimitiveVariables( samples[0], primVarList, messageContext );
407449
}

src/IECoreRenderMan/GeometryAlgo.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ class ConverterDescription
9090

9191
};
9292

93-
/// PrimitiveVariable conversion
93+
/// Primitive conversion helpers
9494
/// ============================
9595

96-
void convertPrimitiveVariables( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList, const std::string &messageContext = "GeometryAlgo::convertPrimitiveVariables" );
97-
void convertPrimitiveVariables( const std::vector<const IECoreScene::Primitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVarList, const std::string &messageContext = "GeometryAlgo::convertPrimitiveVariables" );
96+
/// Primitive converters should call this function before doing their own type-specific conversion.
97+
void convertPrimitive( const IECoreScene::Primitive *primitive, RtPrimVarList &primVarList, const std::string &messageContext );
98+
void convertPrimitive( const std::vector<const IECoreScene::Primitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVarList, const std::string &messageContext );
9899

99100
} // namespace IECoreRenderMan::GeometryAlgo

src/IECoreRenderMan/MeshAlgo.cpp

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,6 @@ int smoothTriangles( const IECoreScene::MeshPrimitive *mesh, const std::string &
122122

123123
RtUString convertMeshTopology( const IECoreScene::MeshPrimitive *mesh, RtPrimVarList &primVars, const std::string &messageContext )
124124
{
125-
primVars.SetDetail(
126-
mesh->variableSize( PrimitiveVariable::Uniform ),
127-
mesh->variableSize( PrimitiveVariable::Vertex ),
128-
mesh->variableSize( PrimitiveVariable::Varying ),
129-
mesh->variableSize( PrimitiveVariable::FaceVarying )
130-
);
131-
132125
primVars.SetIntegerDetail( Loader::strings().k_Ri_nvertices, mesh->verticesPerFace()->readable().data(), RtDetailType::k_uniform );
133126
primVars.SetIntegerDetail( Loader::strings().k_Ri_vertices, mesh->vertexIds()->readable().data(), RtDetailType::k_facevarying );
134127

@@ -207,16 +200,14 @@ RtUString convertMeshTopology( const IECoreScene::MeshPrimitive *mesh, RtPrimVar
207200

208201
RtUString convertStaticMesh( const IECoreScene::MeshPrimitive *mesh, RtPrimVarList &primVars, const std::string &messageContext )
209202
{
210-
const RtUString result = convertMeshTopology( mesh, primVars, messageContext );
211-
GeometryAlgo::convertPrimitiveVariables( mesh, primVars, messageContext );
212-
return result;
203+
GeometryAlgo::convertPrimitive( mesh, primVars, messageContext );
204+
return convertMeshTopology( mesh, primVars, messageContext );
213205
}
214206

215207
RtUString convertAnimatedMesh( const std::vector<const IECoreScene::MeshPrimitive *> &samples, const std::vector<float> &sampleTimes, RtPrimVarList &primVars, const std::string &messageContext )
216208
{
217-
const RtUString result = convertMeshTopology( samples[0], primVars, messageContext );
218-
GeometryAlgo::convertPrimitiveVariables( reinterpret_cast<const std::vector<const IECoreScene::Primitive *> &>( samples ), sampleTimes, primVars, messageContext );
219-
return result;
209+
GeometryAlgo::convertPrimitive( reinterpret_cast<const std::vector<const IECoreScene::Primitive *> &>( samples ), sampleTimes, primVars, messageContext );
210+
return convertMeshTopology( samples[0], primVars, messageContext );;
220211
}
221212

222213
GeometryAlgo::ConverterDescription<MeshPrimitive> g_meshConverterDescription( convertStaticMesh, convertAnimatedMesh );

0 commit comments

Comments
 (0)