Skip to content

Commit 5095445

Browse files
committed
LiveScene: Support for ParticleSprite as PointsPrimitive.
1 parent 4678665 commit 5095445

File tree

2 files changed

+82
-11
lines changed

2 files changed

+82
-11
lines changed

src/IECoreNuke/LiveScene.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636

3737
#include "DDImage/Scene.h"
3838
#include "DDImage/Execute.h"
39+
#include "DDImage/ParticleOp.h"
3940

4041
#include "IECoreNuke/Convert.h"
4142
#include "IECoreNuke/MeshFromNuke.h"
43+
#include "IECoreNuke/FromNukePointsConverter.h"
4244

4345
#include "IECore/Exception.h"
4446
#include "IECore/NullObject.h"
@@ -204,7 +206,6 @@ unsigned LiveScene::objects( const double* time) const
204206
{
205207
frame = m_op->outputContext().frame();
206208
}
207-
208209
cacheGeometryList( frame );
209210

210211
DD::Image::Hash h;
@@ -246,7 +247,6 @@ DD::Image::GeoInfo* LiveScene::object( const unsigned& index, const double* time
246247
{
247248
frame = m_op->outputContext().frame();
248249
}
249-
250250
cacheGeometryList( frame );
251251

252252
DD::Image::Hash h;
@@ -305,13 +305,18 @@ DD::Image::GeometryList LiveScene::geometryList( const double& frame ) const
305305
{
306306
// Nuke Geometry API is not thread safe so we need to use a mutex here to avoid crashes.
307307
tbb::recursive_mutex::scoped_lock l( g_mutex );
308-
auto result = geometryList( m_op, frame );
308+
DD::Image::GeometryList result;
309309

310-
if ( !result.objects() && m_op->input( 0 ) )
310+
if( m_op->input0() && m_op->input0()->particleOp() )
311311
{
312312
auto particleToGeo = Op::create( "ParticleToGeo", m_op );
313+
particleToGeo->set_input( 0, m_op->input0() );
313314
result = geometryList( particleToGeo, frame );
314315
}
316+
else
317+
{
318+
result = geometryList( m_op, frame );
319+
}
315320

316321
return result;
317322
}
@@ -388,7 +393,6 @@ void LiveScene::writeBound( const Imath::Box3d &bound, double time )
388393

389394
ConstDataPtr LiveScene::readTransform( double time ) const
390395
{
391-
392396
for( unsigned i=0; i < objects( &time ); ++i )
393397
{
394398
auto nameValue = geoInfoPath( i );
@@ -487,15 +491,27 @@ bool LiveScene::hasObject() const
487491

488492
ConstObjectPtr LiveScene::readObject( double time, const IECore::Canceller *canceller) const
489493
{
490-
for( unsigned i=0; i < geometryList().objects(); ++i )
494+
for( unsigned i=0; i < objects(); ++i )
491495
{
492496
auto nameValue = geoInfoPath( i );
493497
auto result = m_pathMatcher.match( nameValue );
494498
if ( result == IECore::PathMatcher::ExactMatch )
495499
{
496-
auto geoInfo = geometryList( &time ).object( i );
497-
MeshFromNukePtr converter = new IECoreNuke::MeshFromNuke( &geoInfo );
498-
return converter->convert();
500+
auto geoInfo = object( i, &time );
501+
if ( !geoInfo )
502+
{
503+
return IECore::NullObject::defaultNullObject();
504+
}
505+
if ( geoInfo->primitives() == 1 && ( geoInfo->primitive( 0 )->getPrimitiveType() == DD::Image::PrimitiveType::eParticlesSprite ) )
506+
{
507+
auto converter = new IECoreNuke::FromNukePointsConverter( geoInfo, m_op->input0() );
508+
return converter->convert();
509+
}
510+
else
511+
{
512+
MeshFromNukePtr converter = new IECoreNuke::MeshFromNuke( geoInfo );
513+
return converter->convert();
514+
}
499515
}
500516
}
501517

@@ -514,7 +530,6 @@ void LiveScene::writeObject( const Object *object, double time )
514530

515531
void LiveScene::childNames( NameList &childNames ) const
516532
{
517-
518533
childNames.clear();
519534
std::vector<std::string> allPaths;
520535

test/IECoreNuke/SceneCacheWriterTest.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ def temporaryDirectory( self ) :
6161

6262
return self.__temporaryDirectory
6363

64+
def testWriteEmptyScene( self ):
65+
66+
outputFile = os.path.join( self.temporaryDirectory(), "empty.scc" )
67+
68+
writer = nuke.createNode( "WriteGeo" )
69+
writer["file"].fromScript( outputFile )
70+
71+
nuke.execute( writer, 1001, 1001 )
72+
73+
self.assertTrue( os.path.exists( outputFile ) )
74+
75+
scene = IECoreScene.SharedSceneInterfaces.get( outputFile )
76+
self.assertEqual( scene.childNames(), [] )
77+
6478
def testWriteSimpleSphere( self ):
6579

6680
outputFile = os.path.join( self.temporaryDirectory(), "sphere.scc" )
@@ -88,7 +102,6 @@ def testWriteSimpleSphere( self ):
88102

89103
self.assertEqual( mesh.topologyHash(), liveSceneMesh.topologyHash() )
90104

91-
92105
def testWriteSceneCacheReader( self ):
93106
import random
94107
import IECoreScene
@@ -121,6 +134,49 @@ def testWriteSceneCacheReader( self ):
121134
pointIndex = random.choice( range( len( mesh["P"].data ) ) )
122135
self.assertAlmostEqual( mesh["P"].data[pointIndex], expectedMesh["P"].data[pointIndex], 4 )
123136

137+
def testWriteParticle( self ):
138+
139+
outputFile = os.path.join( self.temporaryDirectory(), "particle.scc" )
140+
141+
noise = nuke.createNode( "Noise")
142+
card = nuke.createNode( "Card2" )
143+
card.setInput( 0, noise )
144+
particle = nuke.createNode( "ParticleEmitter" )
145+
particle.setInput( 1, card )
146+
particle["size_variation"].setValue( 2 )
147+
particle["color_from_texture"].setValue( True )
148+
particle["spread"].setValue( .3 )
149+
writer = nuke.createNode( "WriteGeo" )
150+
writer["file"].fromScript( outputFile )
151+
152+
nuke.execute( writer, 0, 24 )
153+
154+
self.assertTrue( os.path.exists( outputFile ) )
155+
156+
scene = IECoreScene.SharedSceneInterfaces.get( outputFile )
157+
158+
self.assertEqual( scene.childNames(), ["object0"] )
159+
160+
pointsPrim = scene.scene( ["object0",] ).readObject( 1 )
161+
self.assertEqual( set( pointsPrim.keys() ), set( ["Cs", "P", "pid", "width", "velocity", "alpha"] ) )
162+
163+
self.assertEqual( pointsPrim.numPoints, 100 )
164+
self.assertEqual( scene.scene( ["object0",] ).readObject( 0.04 ).numPoints, 10 )
165+
self.assertEqual( scene.scene( ["object0",] ).readObject( 0.5 ).numPoints, 100 )
166+
167+
self.assertAlmostEqual( pointsPrim["P"].data[12], imath.V3f(-0.559, 1.797, 1.677), delta=.015 )
168+
self.assertAlmostEqual( pointsPrim["Cs"].data[21], imath.Color4f(0.241325, 0.241325, 0.241325, 1), delta=.015 )
169+
self.assertAlmostEqual( pointsPrim["alpha"].data[72], 1.0, delta=.015 )
170+
self.assertAlmostEqual( pointsPrim["width"].data[99], .105, delta=.015 )
171+
self.assertAlmostEqual( pointsPrim["pid"].data[92], 197, delta=.015 )
172+
self.assertAlmostEqual( pointsPrim["velocity"].data[72], imath.V3f(-18.424, 4.602, 14.675), delta=.015 )
173+
174+
def assertAlmostEqual( self, left, right, delta=None ):
175+
if isinstance( left, ( imath.V3f, imath.Color3f, imath.Color4f ) ):
176+
for index, _ in enumerate( left ):
177+
super( SceneCacheWriterTest, self ).assertAlmostEqual( left[index], right[index], delta=delta )
178+
else:
179+
super( SceneCacheWriterTest, self ).assertAlmostEqual( left, right, delta=delta )
124180

125181
if __name__ == "__main__":
126182
unittest.main()

0 commit comments

Comments
 (0)