IECore::ImagePrimitivePtr IECoreRI::SXRendererImplementation::shadePlaneToImage( const V2i &resolution ) const { IECore::CompoundDataPtr result = shadePlane( resolution ); Box2i window = Box2i( V2i( 0, 0 ), V2i( resolution[0] - 1, resolution[1] - 1 ) ); IECore::ImagePrimitivePtr img = new IECore::ImagePrimitive( window, window ); IECore::FloatVectorDataPtr rData = img->createChannel<float>( "R" ); IECore::FloatVectorDataPtr gData = img->createChannel<float>( "G" ); IECore::FloatVectorDataPtr bData = img->createChannel<float>( "B" ); IECore::FloatVectorDataPtr aData = img->createChannel<float>( "A" ); std::vector<float> &r = rData->writable(); std::vector<float> &g = gData->writable(); std::vector<float> &b = bData->writable(); std::vector<float> &a = aData->writable(); unsigned numPoints = resolution[0] * resolution[1]; r.resize( numPoints ); g.resize( numPoints ); b.resize( numPoints ); a.resize( numPoints ); IECore::Color3fVectorDataPtr cData = result->member<Color3fVectorData>( "Ci", false ); IECore::Color3fVectorDataPtr oData = result->member<Color3fVectorData>( "Oi", false ); if( !cData || !oData ) { throw( Exception( "The renderer didn't return Ci/Oi when shading the points." ) ); } const std::vector<Color3f> &c = cData->readable(); const std::vector<Color3f> &o = oData->readable(); if( c.size() != numPoints ) { throw( Exception( boost::str( boost::format( "The renderer didn't return the right number of shaded points. (%d but should be %d)." ) % c.size() % numPoints ) ) ); } for( std::vector<V3f>::size_type i=0; i<c.size(); i++ ) { r[i] = c[i][0]; g[i] = c[i][1]; b[i] = c[i][2]; a[i] = ( o[i][0] + o[i][1] + o[i][2] ) / 3.0f; } return img; }
IECore::ObjectPtr FromMayaSkinClusterConverter::doConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const { MStatus stat; // our data storage objects IECore::StringVectorDataPtr influenceNamesData = new IECore::StringVectorData(); IECore::M44fVectorDataPtr influencePoseData = new IECore::M44fVectorData(); IECore::IntVectorDataPtr pointIndexOffsetsData = new IECore::IntVectorData(); IECore::IntVectorDataPtr pointInfluenceCountsData = new IECore::IntVectorData(); IECore::IntVectorDataPtr pointInfluenceIndicesData = new IECore::IntVectorData(); IECore::FloatVectorDataPtr pointInfluenceWeightsData = new IECore::FloatVectorData(); // get a skin cluster fn MFnSkinCluster skinClusterFn(object); MDagPathArray influencePaths; skinClusterFn.influenceObjects(influencePaths); // get the influence names int influencesCount = influencePaths.length(); influenceNamesData->writable().reserve( influencesCount ); InfluenceName in = (InfluenceName)m_influenceNameParameter->getNumericValue(); switch( in ) { case Partial : { for (int i=0; i < influencesCount; i++) { influenceNamesData->writable().push_back( influencePaths[i].partialPathName(&stat).asChar() ); } break; } case Full : { for (int i=0; i < influencesCount; i++) { influenceNamesData->writable().push_back( influencePaths[i].fullPathName(&stat).asChar() ); } break; } } // extract bind pose MFnDependencyNode skinClusterNodeFn( object ); MPlug bindPreMatrixArrayPlug = skinClusterNodeFn.findPlug( "bindPreMatrix", true, &stat ); for (int i=0; i < influencesCount; i++) { MPlug bindPreMatrixElementPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( skinClusterFn.indexForInfluenceObject( influencePaths[i], NULL ), &stat); MObject matObj; bindPreMatrixElementPlug.getValue( matObj ); MFnMatrixData matFn( matObj, &stat ); MMatrix mat = matFn.matrix(); Imath::M44f cmat = IECore::convert<Imath::M44f>( mat ); influencePoseData->writable().push_back( cmat ); } // extract the skinning information // get the first input geometry to the skin cluster // TODO: if needed, extend this to retrieve more than one output geometry MObjectArray outputGeoObjs; stat = skinClusterFn.getOutputGeometry( outputGeoObjs ); if (! stat) { throw IECore::Exception( "FromMayaSkinClusterConverter: skinCluster node does not have any output geometry!" ); } // get the dag path to the first object MFnDagNode dagFn( outputGeoObjs[0] ); MDagPath geoPath; dagFn.getPath( geoPath ); // generate a geo iterator for the components MItGeometry geoIt( outputGeoObjs[0] ); int currentOffset = 0; // loop through all the points of the geometry to extract their bind information for ( ; !geoIt.isDone(); geoIt.next() ) { MObject pointObj = geoIt.currentItem( &stat ); MDoubleArray weights; unsigned int weightsCount; skinClusterFn.getWeights( geoPath, pointObj, weights, weightsCount ); int pointInfluencesCount = 0; for ( int influenceId = 0; influenceId < int( weightsCount ); influenceId++ ) { // ignore zero weights, we are generating a compressed (non-sparse) representation of the weights /// \todo: use a parameter to specify a threshold value rather than 0.0 if ( weights[influenceId] != 0.0 ) { pointInfluencesCount++; pointInfluenceWeightsData->writable().push_back( float( weights[influenceId] ) ); pointInfluenceIndicesData->writable().push_back( influenceId ); } } pointIndexOffsetsData->writable().push_back( currentOffset ); pointInfluenceCountsData->writable().push_back( pointInfluencesCount ); currentOffset += pointInfluencesCount; } // put all our results in a smooth skinning data object return new IECore::SmoothSkinningData( influenceNamesData, influencePoseData, pointIndexOffsetsData, pointInfluenceCountsData, pointInfluenceIndicesData, pointInfluenceWeightsData ); }
///\todo: It seems that if a JPG is written with RGBA channels the output is wrong but it should be supported. Find out why and fix it. /// There is a test case in ImageWriterTest which checks the output of the jpg writer against an incorrect image and it will fail if it is equal to the writer output. void ImageWriter::execute( const Contexts &contexts ) const { if( !inPlug()->getInput<ImagePlug>() ) { throw IECore::Exception( "No input image." ); } // Loop over the execution contexts... for( Contexts::const_iterator it = contexts.begin(), eIt = contexts.end(); it != eIt; it++ ) { Context::Scope scopedContext( it->get() ); std::string fileName = fileNamePlug()->getValue(); fileName = (*it)->substitute( fileName ); boost::shared_ptr< ImageOutput > out( ImageOutput::create( fileName.c_str() ) ); if ( !out ) { throw IECore::Exception( boost::str( boost::format( "Invalid filename: %s" ) % fileName ) ); } // Grab the intersection of the channels from the "channels" plug and the image input to see which channels we are to write out. IECore::ConstStringVectorDataPtr channelNamesData = inPlug()->channelNamesPlug()->getValue(); std::vector<std::string> maskChannels = channelNamesData->readable(); channelsPlug()->maskChannels( maskChannels ); const int nChannels = maskChannels.size(); // Get the image channel data. IECore::ImagePrimitivePtr imagePtr( inPlug()->image() ); // Get the image's display window. const Imath::Box2i displayWindow( imagePtr->getDisplayWindow() ); const int displayWindowWidth = displayWindow.size().x+1; const int displayWindowHeight = displayWindow.size().y+1; // Get the image's data window and if it then set a flag. bool imageIsBlack = false; Imath::Box2i dataWindow( imagePtr->getDataWindow() ); if ( inPlug()->dataWindowPlug()->getValue().isEmpty() ) { dataWindow = displayWindow; imageIsBlack = true; } int dataWindowWidth = dataWindow.size().x+1; int dataWindowHeight = dataWindow.size().y+1; // Create the image header. ImageSpec spec( dataWindowWidth, dataWindowHeight, nChannels, TypeDesc::FLOAT ); // Add the channel names to the header whilst getting pointers to the channel data. std::vector<const float*> channelPtrs; spec.channelnames.clear(); for ( std::vector<std::string>::iterator channelIt( maskChannels.begin() ); channelIt != maskChannels.end(); channelIt++ ) { spec.channelnames.push_back( *channelIt ); IECore::FloatVectorDataPtr dataPtr = imagePtr->getChannel<float>( *channelIt ); channelPtrs.push_back( &(dataPtr->readable()[0]) ); // OIIO has a special attribute for the Alpha and Z channels. If we find some, we should tag them... if ( *channelIt == "A" ) { spec.alpha_channel = channelIt-maskChannels.begin(); } else if ( *channelIt == "Z" ) { spec.z_channel = channelIt-maskChannels.begin(); } } // Specify the display window. spec.full_x = displayWindow.min.x; spec.full_y = displayWindow.min.y; spec.full_width = displayWindowWidth; spec.full_height = displayWindowHeight; spec.x = dataWindow.min.x; spec.y = dataWindow.min.y; if ( !out->open( fileName, spec ) ) { throw IECore::Exception( boost::str( boost::format( "Could not open \"%s\", error = %s" ) % fileName % out->geterror() ) ); } // Only allow tiled output if our file format supports it. int writeMode = writeModePlug()->getValue() & out->supports( "tile" ); if ( writeMode == Scanline ) { // Create a buffer for the scanline. float scanline[ nChannels*dataWindowWidth ]; if ( imageIsBlack ) { memset( scanline, 0, sizeof(float) * nChannels*dataWindowWidth ); for ( int y = spec.y; y < spec.y + dataWindowHeight; ++y ) { if ( !out->write_scanline( y, 0, TypeDesc::FLOAT, &scanline[0] ) ) { throw IECore::Exception( boost::str( boost::format( "Could not write scanline to \"%s\", error = %s" ) % fileName % out->geterror() ) ); } } } else { // Interleave the channel data and write it by scanline to the file. for ( int y = spec.y; y < spec.y + dataWindowHeight; ++y ) { for ( std::vector<const float *>::iterator channelDataIt( channelPtrs.begin() ); channelDataIt != channelPtrs.end(); channelDataIt++ ) { float *outPtr = &scanline[0] + (channelDataIt - channelPtrs.begin()); // The pointer that we are writing to. // The row that we are reading from is flipped (in the Y) as we use a different image space internally to OpenEXR and OpenImageIO. const float *inRowPtr = (*channelDataIt) + ( y - spec.y ) * dataWindowWidth; const int inc = channelPtrs.size(); for ( int x = 0; x < dataWindowWidth; ++x, outPtr += inc ) { *outPtr = *inRowPtr++; } } if ( !out->write_scanline( y, 0, TypeDesc::FLOAT, &scanline[0] ) ) { throw IECore::Exception( boost::str( boost::format( "Could not write scanline to \"%s\", error = %s" ) % fileName % out->geterror() ) ); } } } } // Tiled output else { // Create a buffer for the tile. const int tileSize = ImagePlug::tileSize(); float tile[ nChannels*tileSize*tileSize ]; if ( imageIsBlack ) { memset( tile, 0, sizeof(float) * nChannels*tileSize*tileSize ); for ( int tileY = 0; tileY < dataWindowHeight; tileY += tileSize ) { for ( int tileX = 0; tileX < dataWindowWidth; tileX += tileSize ) { if ( !out->write_tile( tileX+dataWindow.min.x, tileY+spec.y, 0, TypeDesc::FLOAT, &tile[0] ) ) { throw IECore::Exception( boost::str( boost::format( "Could not write tile to \"%s\", error = %s" ) % fileName % out->geterror() ) ); } } } } else { // Interleave the channel data and write it to the file tile-by-tile. for ( int tileY = 0; tileY < dataWindowHeight; tileY += tileSize ) { for ( int tileX = 0; tileX < dataWindowWidth; tileX += tileSize ) { float *outPtr = &tile[0]; const int r = std::min( tileSize+tileX, dataWindowWidth ); const int t = std::min( tileSize+tileY, dataWindowHeight ); for ( int y = 0; y < t; ++y ) { for ( std::vector<const float *>::iterator channelDataIt( channelPtrs.begin() ); channelDataIt != channelPtrs.end(); channelDataIt++ ) { const int inc = channelPtrs.size(); const float *inRowPtr = (*channelDataIt) + ( tileY + t - y - 1 ) * dataWindowWidth; for ( int x = 0; x < r; ++x, outPtr += inc ) { *outPtr = *inRowPtr+(tileX+x); } } } if ( !out->write_tile( tileX+dataWindow.min.x, tileY+spec.y, 0, TypeDesc::FLOAT, &tile[0] ) ) { throw IECore::Exception( boost::str( boost::format( "Could not write tile to \"%s\", error = %s" ) % fileName % out->geterror() ) ); } } } } } out->close(); } }
void LensDistortOp::begin( const CompoundObject * operands ) { // Get the lens model parameters. IECore::CompoundObjectPtr lensModelParams( runTimeCast<CompoundObject>( lensParameter()->getValue() ) ); // Load the lens object. m_lensModel = LensModel::create( lensModelParams ); m_lensModel->validate(); // Get the distortion mode. m_mode = m_modeParameter->getNumericValue(); // Get our image information. assert( runTimeCast< ImagePrimitive >(inputParameter()->getValue()) ); ImagePrimitive *inputImage = static_cast<ImagePrimitive *>( inputParameter()->getValue() ); Imath::Box2i dataWindow( inputImage->getDataWindow() ); Imath::Box2i displayWindow( inputImage->getDisplayWindow() ); double displayWH[2] = { static_cast<double>( displayWindow.size().x + 1 ), static_cast<double>( displayWindow.size().y + 1 ) }; double displayOrigin[2] = { static_cast<double>( displayWindow.min[0] ), static_cast<double>( displayWindow.min[1] ) }; // Get the distorted window. // As the LensModel::bounds() method requires that the display window has it's origin at (0,0) in the bottom left of the image and the IECore::ImagePrimitive has it's origin in the top left, // convert to the correct image space and offset if by the display window's origin if it is non-zero. Imath::Box2i distortionSpaceBox( Imath::V2i( dataWindow.min[0] - displayWindow.min[0], displayWindow.size().y - ( dataWindow.max[1] - displayWindow.min[1] ) ), Imath::V2i( dataWindow.max[0] - displayWindow.min[0], displayWindow.size().y - ( dataWindow.min[1] - displayWindow.min[1] ) ) ); // Calculate the distorted data window. Imath::Box2i distortedWindow = m_lensModel->bounds( m_mode, distortionSpaceBox, ( displayWindow.size().x + 1 ), ( displayWindow.size().y + 1 ) ); // Convert the distorted data window back to the same image space as IECore::ImagePrimitive. m_distortedDataWindow = Imath::Box2i( Imath::V2i( distortedWindow.min[0] + displayWindow.min[0], ( displayWindow.size().y - distortedWindow.max[1] ) + displayWindow.min[1] ), Imath::V2i( distortedWindow.max[0] + displayWindow.min[0], ( displayWindow.size().y - distortedWindow.min[1] ) + displayWindow.min[1] ) ); // Compute a 2D cache of the warped points for use in the warp() method. IECore::FloatVectorDataPtr cachePtr = new IECore::FloatVectorData; std::vector<float> &cache( cachePtr->writable() ); cache.resize( ( m_distortedDataWindow.size().x + 1 ) * ( m_distortedDataWindow.size().y + 1 ) * 2 ); // We interleave the X and Y vector components within the cache. for( int y = distortedWindow.max.y, pixelIndex = 0; y >= distortedWindow.min.y; --y ) { for( int x = distortedWindow.min.x; x <= distortedWindow.max.x; ++x ) { // Convert to UV space with the origin in the bottom left. Imath::V2f p( Imath::V2f( x, y ) ); Imath::V2d uv( p[0] / displayWH[0], p[1] / displayWH[1] ); // Get the distorted uv coordinate. Imath::V2d duv( m_mode == kDistort ? m_lensModel->distort( uv ) : m_lensModel->undistort( uv ) ); // Transform it to image space. p = Imath::V2f( duv[0] * displayWH[0] + displayOrigin[0], ( ( displayWH[1] - 1. ) - ( duv[1] * displayWH[1] ) ) + displayOrigin[1] ); cache[pixelIndex++] = p[0]; cache[pixelIndex++] = p[1]; } } m_cachePtr = cachePtr; }