IECore::CompoundDataPtr GXEvaluator::evaluate( const IECore::FloatVectorData *s, const IECore::FloatVectorData *t, const std::vector<std::string> &primVarNames ) const { size_t numPoints = s->readable().size(); if( t->readable().size() != numPoints ) { throw InvalidArgumentException( "s and t must have the same length" ); } buildSTEvaluator(); MeshPrimitiveEvaluator::ResultPtr evaluatorResult = staticPointerCast<MeshPrimitiveEvaluator::Result>( m_stEvaluator->createResult() ); IntVectorDataPtr fData = new IntVectorData; FloatVectorDataPtr uData = new FloatVectorData; FloatVectorDataPtr vData = new FloatVectorData; BoolVectorDataPtr statusData = new BoolVectorData; std::vector<int> &fWritable = fData->writable(); fWritable.resize( numPoints ); std::vector<float> &uWritable = uData->writable(); uWritable.resize( numPoints ); std::vector<float> &vWritable = vData->writable(); vWritable.resize( numPoints ); std::vector<bool> &statusWritable = statusData->writable(); statusWritable.resize( numPoints ); const std::vector<float> &sReadable = s->readable(); const std::vector<float> &tReadable = t->readable(); const PrimitiveVariable &uPrimVar = m_stEvaluator->primitive()->variables.find( "u" )->second; const PrimitiveVariable &vPrimVar = m_stEvaluator->primitive()->variables.find( "v" )->second; for( size_t i=0; i<numPoints; i++ ) { bool success = m_stEvaluator->pointAtUV( Imath::V2f( sReadable[i], tReadable[i] ), evaluatorResult ); // dividing by 2 maps from the triangle index to the original face index of the mesh before it // was triangulated - we can guarantee this because the original mesh was all quads. fWritable[i] = success ? evaluatorResult->triangleIndex() / 2 : 0; uWritable[i] = success ? evaluatorResult->floatPrimVar( uPrimVar ) : 0; vWritable[i] = success ? evaluatorResult->floatPrimVar( vPrimVar ) : 0; statusWritable[i] = success; } CompoundDataPtr result = evaluate( fData, uData, vData, primVarNames ); result->writable()["gxStatus"] = statusData; return result; }
void MeshFaceFilterOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundObject * operands ) { ObjectPtr object = m_filterParameter->getValue(); if( !object ) { throw InvalidArgumentException( "MeshFaceFilterOp : Invalid filter input object." ); } BoolVectorDataPtr filterData = runTimeCast<BoolVectorData>( object ); if( !filterData ) { throw InvalidArgumentException( "MeshFaceFilterOp : The filter input is not a BoolVectorData object." ); } const std::vector<bool>& filter = filterData->readable(); if( filter.size() != mesh->numFaces() ) { throw InvalidArgumentException( "MeshFaceFilterOp : The filter must have one entry per mesh face." ); } // find all verts/face verts touched by an active face: const std::vector<int>& verticesPerFace = mesh->verticesPerFace()->readable(); const std::vector<int>& vertexIds = mesh->vertexIds()->readable(); size_t numVerts = mesh->variableSize( PrimitiveVariable::Vertex ); BoolVectorDataPtr activeVertsData = new BoolVectorData(); BoolVectorDataPtr activeFaceVertsData = new BoolVectorData(); std::vector<bool>& activeVerts = activeVertsData->writable(); std::vector<bool>& activeFaceVerts = activeFaceVertsData->writable(); activeVerts.resize( numVerts, false ); activeFaceVerts.resize( vertexIds.size(), false ); // why don't we work out the new topology while we're at it? IntVectorDataPtr newVerticesPerFaceData = new IntVectorData(); IntVectorDataPtr newVertexIdsData = new IntVectorData(); std::vector<int>& newVerticesPerFace = newVerticesPerFaceData->writable(); std::vector<int>& newVertexIds = newVertexIdsData->writable(); size_t vertNum( 0 ); for( size_t face=0; face < mesh->numFaces(); ++face ) { size_t polyNumVerts = verticesPerFace[face]; if( filter[ face ] ) { newVerticesPerFace.push_back( polyNumVerts ); for( size_t j=0; j < polyNumVerts; ++j ) { int vertId = vertexIds[ vertNum + j ]; activeVerts[vertId] = true; activeFaceVerts[ vertNum + j ] = true; newVertexIds.push_back( vertId ); } } vertNum += polyNumVerts; } // Right. So we've gotta chuck away the vertices that aren't touched any more which means resizing arrays and // randomly removing their elements. Lets find a mapping between the old arrays and the new ones: std::vector<int> vertMapping( activeVerts.size() ); int idx = 0; for( size_t i=0; i < activeVerts.size(); ++i ) { vertMapping[i] = idx; idx += int( activeVerts[i] ); } // use this to remap the new vertex ids: for( size_t i=0; i < newVertexIds.size(); ++i ) { newVertexIds[i] = vertMapping[ newVertexIds[i] ]; } // decimate primvars: VectorDataFilterOpPtr filterOp = new VectorDataFilterOp(); filterOp->copyParameter()->setTypedValue( false ); // we keep track of all the primitive variables we've filtered so far, in case some of the // actual data buffers are duplicated: std::set< IECore::DataPtr > primvarsDone; for( IECore::PrimitiveVariableMap::iterator it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { if( primvarsDone.find( it->second.data ) != primvarsDone.end() ) { continue; } switch( it->second.interpolation ) { case PrimitiveVariable::Constant : break; // nothing to do case PrimitiveVariable::Uniform : filterOp->parameters()->parameter<Parameter>( "filter" )->setValue( filterData ); filterOp->inputParameter()->setValue( it->second.data ); filterOp->operate(); break; case PrimitiveVariable::Vertex : case PrimitiveVariable::Varying: filterOp->parameters()->parameter<Parameter>( "filter" )->setValue( activeVertsData ); filterOp->inputParameter()->setValue( it->second.data ); filterOp->operate(); break; case PrimitiveVariable::FaceVarying: filterOp->parameters()->parameter<Parameter>( "filter" )->setValue( activeFaceVertsData ); filterOp->inputParameter()->setValue( it->second.data ); filterOp->operate(); break; default : break; } primvarsDone.insert( it->second.data ); } // set new topology: mesh->setTopology( newVerticesPerFaceData, newVertexIdsData, mesh->interpolation() ); }