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  );
}
Esempio n. 3
0
///\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();
	}
}
Esempio n. 4
0
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;
}