diff --git a/src/GafferScene/Instancer.cpp b/src/GafferScene/Instancer.cpp index b0d1b93c82f..05ece8d25b4 100644 --- a/src/GafferScene/Instancer.cpp +++ b/src/GafferScene/Instancer.cpp @@ -2729,8 +2729,6 @@ void Instancer::InstancerCapsule::render( IECoreScenePreview::Renderer *renderer const std::vector &instancesForPrototype = engines[0]->instancesForPrototype( root().back() ); const ScenePlug::ScenePath *prototypeRoot = engines[0]->prototypeRoot( root().back() ); - bool hasAttributes = engines[0]->numInstanceAttributes() > 0; - const ScenePlug *prototypesPlug = m_instancer->prototypesPlug(); ObjectVectorPtr prototypesData = new ObjectVector(); @@ -2791,85 +2789,7 @@ void Instancer::InstancerCapsule::render( IECoreScenePreview::Renderer *renderer ); } - // If we stick with this approach in the long run, we need some sort of registry of registry or query - // for whether a renderer supports this special instancer object - or perhaps once we standardize an - // instancer object, all renderers will be required to support it. - bool rendererSupportsInstancerObject = renderer->name() == "Arnold"; - - if( rendererSupportsInstancerObject ) - { - ObjectVectorPtr instanceMatrixData = new ObjectVector(); - std::vector< std::vector * > instanceMatrix; - - for( unsigned int i = 0; i < sampleTimes.size(); i++ ) - { - M44fVectorDataPtr motionKey = new M44fVectorData(); - instanceMatrixData->members().push_back( motionKey ); - instanceMatrix.push_back( &motionKey->writable() ); - } - - std::vector instanceIdsForPrototype; - instanceIdsForPrototype.reserve( instancesForPrototype.size() ); - for( int i : instancesForPrototype ) - { - instanceIdsForPrototype.push_back( engines[0]->instanceId( i ) ); - } - - std::vector< std::vector< int > > pointIndices( sampleTimes.size() ); - - // For the first sample, the pointIndices can just come from instancesForPrototype. - // It's wasteful to duplicate them, but it's better than making all the calls to - // pointIndex() from the loop below. This would all get much simpler if we made it - // an exception to vary pointIndices during the shutter. - pointIndices[0] = instancesForPrototype; - - for( unsigned int i = 1; i < sampleTimes.size(); i++ ) - { - pointIndices[i].reserve( sampleTimes.size() ); - for( int instanceId : instanceIdsForPrototype ) - { - pointIndices[i].push_back( engines[i]->pointIndex( instanceId ) ); - } - } - - // \todo - it seems like there is an opportunity to cut our expansion time by up to half by - // skipping this if we can somehow detect early that the points are not moving. - // - // Currently, our expansion time is a tenth of Arnold's "node init" for a heavy instancer - // though, so it doesn't seem super high priority. - // - // TODO - prep instanceMatrix for the non-Arnold case as well to reduce code duplication? - for( unsigned int i = 0; i < sampleTimes.size(); i++ ) - { - instanceMatrix[i]->reserve( instancesForPrototype.size() ); - for( unsigned int idx = 0; idx < pointIndices[i].size(); idx++ ) - { - int pointIndex = pointIndices[i][idx]; - int prototypeIndex = 0; - if( prototypeIndices.size() ) - { - prototypeIndex = prototypeIndices[ idx ]; - } - - instanceMatrix[i]->push_back( prototypeTransforms[ sampleTimes.size() * prototypeIndex + i ] * engines[i]->instanceTransform( pointIndex ) ); - } - } - - CompoundObjectPtr instanceAttributes = new CompoundObject(); - engines[0]->instanceAttributeVectors( pointIndices[0], *instanceAttributes ); - - IECore::CompoundObjectPtr instancerArguments = new IECore::CompoundObject(); - instancerArguments->members()["isInstancer"] = new BoolData( true ); - instancerArguments->members()["prototypeIndices"] = prototypeIndicesData; - instancerArguments->members()["prototypes"] = prototypesData; - instancerArguments->members()["prototypeAttributes"] = prototypeAttributesData; - instancerArguments->members()["sampleTimes"] = sampleTimesData; - instancerArguments->members()["instanceMatrix"] = instanceMatrixData; - instancerArguments->members()["instanceAttributes"] = instanceAttributes; - - renderer->object( "instancer", instancerArguments.get(), renderer->attributes( new IECore::CompoundObject() ).get() ); - return; - } + bool hasAttributes = engines[0]->numInstanceAttributes() > 0; // If we don't have per-instance attributes, we can pre-prepare renderer attributes ready to go that // depend only on the prototype @@ -2885,58 +2805,64 @@ void Instancer::InstancerCapsule::render( IECoreScenePreview::Renderer *renderer IECoreScenePreview::Renderer::AttributesInterfacePtr attribsStorage; - vector pointTransforms( sampleTimes.size() ); - std::string name; - for( unsigned int idx = 0; idx < instancesForPrototype.size(); idx++ ) - { - int pointIndex = instancesForPrototype[idx]; - int prototypeIndex = 0; - if( prototypeIndices.size() ) + tbb::parallel_for( tbb::blocked_range( 0, instancesForPrototype.size() ), [&]( const tbb::blocked_range &r ) { - prototypeIndex = prototypeIndices[ idx ]; - } + vector pointTransforms( sampleTimes.size() ); + std::string name; - IECoreScenePreview::Renderer::AttributesInterface *attribs; - int instanceId = engines[0]->instanceId( pointIndex ); - if( hasAttributes ) - { - CompoundObjectPtr currentAttributes = new CompoundObject(); - engines[0]->instanceAttributes( pointIndex, *currentAttributes ); - for( auto &i : static_cast< CompoundObject* >( prototypeAttributes[prototypeIndex].get() )->members() ) + for( size_t idx = r.begin(); idx != r.end(); ++idx ) { - currentAttributes->members()[i.first] = i.second; - } + int pointIndex = instancesForPrototype[idx]; - attribsStorage = renderer->attributes( currentAttributes.get() ); - attribs = attribsStorage.get(); - } - else - { - attribs = prototypeRendererAttribs[prototypeIndex].get(); - } + int prototypeIndex = 0; + if( prototypeIndices.size() ) + { + prototypeIndex = prototypeIndices[ idx ]; + } - // We are running inside a procedural, so we don't need globally unique name. We are making a whole - // lot of these names for instances, so we make these names as absolutely minimal as possible. - name.resize( std::numeric_limits< int >::digits10 + 1 ); - name.resize( std::to_chars( &name[0], &(*name.end()), instanceId ).ptr - &name[0] ); + IECoreScenePreview::Renderer::AttributesInterface *attribs; + int instanceId = engines[0]->instanceId( pointIndex ); + if( hasAttributes ) + { + CompoundObjectPtr currentAttributes = new CompoundObject(); + engines[0]->instanceAttributes( pointIndex, *currentAttributes ); + for( auto &i : static_cast< CompoundObject* >( prototypeAttributes[prototypeIndex].get() )->members() ) + { + currentAttributes->members()[i.first] = i.second; + } - IECoreScenePreview::Renderer::ObjectInterfacePtr objectInterface = renderer->object( name, prototypes[prototypeIndex].get(), attribs ); + attribsStorage = renderer->attributes( currentAttributes.get() ); + attribs = attribsStorage.get(); + } + else + { + attribs = prototypeRendererAttribs[prototypeIndex].get(); + } - if( sampleTimes.size() == 1 ) - { - objectInterface->transform( prototypeTransforms[ prototypeIndex ] * engines[0]->instanceTransform( pointIndex ) ); - } - else - { - for( unsigned int i = 0; i < engines.size(); i++ ) - { - int curPointIndex = i == 0 ? pointIndex : engines[i]->pointIndex( instanceId ); - pointTransforms[i] = prototypeTransforms[ prototypeIndex * sampleTimes.size() + i] * engines[i]->instanceTransform( curPointIndex ); - } + // We are running inside a procedural, so we don't need globally unique name. We are making a whole + // lot of these names for instances, so we make these names as absolutely minimal as possible. + name.resize( std::numeric_limits< int >::digits10 + 1 ); + name.resize( std::to_chars( &name[0], &(*name.end()), instanceId ).ptr - &name[0] ); - objectInterface->transform( pointTransforms, sampleTimes ); - } + IECoreScenePreview::Renderer::ObjectInterfacePtr objectInterface = renderer->object( name, prototypes[prototypeIndex].get(), attribs ); - } + if( sampleTimes.size() == 1 ) + { + objectInterface->transform( prototypeTransforms[ prototypeIndex ] * engines[0]->instanceTransform( pointIndex ) ); + } + else + { + for( unsigned int i = 0; i < engines.size(); i++ ) + { + int curPointIndex = i == 0 ? pointIndex : engines[i]->pointIndex( instanceId ); + pointTransforms[i] = prototypeTransforms[ prototypeIndex * sampleTimes.size() + i] * engines[i]->instanceTransform( curPointIndex ); + } + + objectInterface->transform( pointTransforms, sampleTimes ); + } + + } + } + ); }