3838
3939#include " IECoreScene/PointsPrimitive.h"
4040
41+ #include " DDImage/ParticleOp.h"
42+
4143using namespace IECoreNuke ;
4244using namespace IECore ;
4345using namespace IECoreScene ;
46+ using namespace DD ::Image;
4447
45- FromNukePointsConverter::FromNukePointsConverter ( const DD::Image::GeoInfo *geo )
46- : FromNukeConverter( " Converts nuke meshes to IECore meshes ." ), m_geo( geo )
48+ FromNukePointsConverter::FromNukePointsConverter ( const DD::Image::GeoInfo *geo, DD::Image::Op* op )
49+ : FromNukeConverter( " Converts nuke ParticleSprites to IECore PointsPrimitive ." ), m_geo( geo ), m_op( op )
4750{
4851}
4952
@@ -66,15 +69,87 @@ IECore::ObjectPtr FromNukePointsConverter::doConversion( IECore::ConstCompoundOb
6669
6770 // get colour
6871 const DD::Image::Attribute *colorAttr = m_geo->get_typed_attribute ( " Cf" , DD::Image::VECTOR4_ATTRIB );
69- if ( colorAttr && colorAttr->size ()== result->getNumPoints () )
72+ if ( colorAttr && colorAttr->size () == result->getNumPoints () )
7073 {
71- Color3fVectorDataPtr colorData = new Color3fVectorData ();
74+ Color4fVectorDataPtr colorData = new Color4fVectorData ();
7275 colorData->writable ().resize ( result->getNumPoints () );
73- std::transform ( colorAttr->vector4_list ->begin (), colorAttr->vector4_list ->end (), colorData->writable ().begin (), IECore::convert<Imath::Color3f , DD::Image::Vector4> );
76+ std::transform ( colorAttr->vector4_list ->begin (), colorAttr->vector4_list ->end (), colorData->writable ().begin (), IECore::convert<Imath::Color4f , DD::Image::Vector4> );
7477 result->variables [" Cs" ] = PrimitiveVariable ( PrimitiveVariable::Vertex, colorData );
78+
79+ // Adding a separate alpha primvar as according to my test
80+ // Cs is a Color3f in Gaffer. While we could also use 3f here, I think it is reasonable
81+ // to combine alpha inside Cs and hope it gets supported by Gaffer and then we can remove
82+ // the alpha primvar.
83+ FloatVectorDataPtr alphaData = new FloatVectorData ();
84+ auto & alpha = alphaData->writable ();
85+ alpha.resize ( result->getNumPoints () );
86+
87+ for ( size_t i=0 ; i < result->getNumPoints (); i++ )
88+ {
89+ alpha[i] = colorAttr->vector4 ( i ).w ;
90+ }
91+ result->variables [" alpha" ] = PrimitiveVariable ( PrimitiveVariable::Vertex, alphaData );
92+ }
93+
94+ // get pid
95+ const DD::Image::Attribute *idAttr = m_geo->get_typed_attribute ( " id" , DD::Image::INT_ATTRIB );
96+ if ( idAttr && idAttr->size () == result->getNumPoints () )
97+ {
98+ IntVectorDataPtr idData = new IntVectorData ();
99+ auto & id = idData->writable ();
100+ id.resize ( result->getNumPoints () );
101+ for ( size_t i=0 ; i < result->getNumPoints (); i++ )
102+ {
103+ id[i] = idAttr->integer ( i );
104+ }
105+ result->variables [" pid" ] = PrimitiveVariable ( PrimitiveVariable::Vertex, idData );
106+ }
107+
108+ // get size/width
109+ const DD::Image::Attribute *sizeAttr = m_geo->get_typed_attribute ( " size" , DD::Image::FLOAT_ATTRIB );
110+ if ( sizeAttr && sizeAttr->size () == result->getNumPoints () )
111+ {
112+ FloatVectorDataPtr widthData = new FloatVectorData ();
113+ auto & width = widthData->writable ();
114+ width.resize ( result->getNumPoints () );
115+
116+ for ( size_t i=0 ; i < result->getNumPoints (); i++ )
117+ {
118+ width[i] = sizeAttr->flt ( i );
119+ }
120+ result->variables [" width" ] = PrimitiveVariable ( PrimitiveVariable::Vertex, widthData );
75121 }
76122
77- // / \todo Other primitive variables
123+ // get vel
124+ // Nuke's particle system seems to be a bit ad-hock rather than integrated in the 3D sub-system.
125+ // To get the particle velocity, we mix the API ( ParticleOp and GeoOp ). Arguably, we could switch
126+ // to use the ParticleOp API for everything but for now I decided to keep accessing what can be using the
127+ // GeoOp/GeoInfo API, hoping that Foundry will ultimately get the particle to geo fully supported.
128+ //
129+ // Another important detail here is that we are using the m_op->input0, this is based on the expectation
130+ // that the LiveScene will always be the client of this kind of converter.
131+ // In which case, the LiveScene is always internal to a GeoOp derived node (LiveSceneHolder or WriteGeo)
132+ auto particleOp = m_op->particleOp ();
133+ if ( particleOp )
134+ {
135+ OutputContext oc;
136+ oc.setFrame ( m_op->outputContext ().frame () );
137+ particleOp->setOutputContext ( oc );
138+ float prevTime, outTime;
139+ const auto particleSystem = particleOp->getParticleSystem (prevTime, outTime, true , nullptr );
140+
141+ V3fVectorDataPtr velData = new V3fVectorData ();
142+ auto & vel = velData->writable ();
143+ vel.resize ( result->getNumPoints () );
144+ for ( size_t i=0 ; i < result->getNumPoints (); i++ )
145+ {
146+ // velocity seems to be calculated per time step so we need to multiply by the frames per second to get velocity compatible with motion blur rendering.
147+ vel[i] = IECore::convert<Imath::V3f>( particleSystem->particleVelocity ( i ) ) * DD::Image::root_real_fps ();
148+ }
149+
150+ result->variables [" velocity" ] = PrimitiveVariable ( PrimitiveVariable::Vertex, velData );
151+ }
152+ // \todo Other primitive variables
78153
79154 return result;
80155}
0 commit comments