Exemple #1
0
	Engine( const Box2i &displayWindow, const Box2i &tileBound, const Box2i &validTileBound, ConstFloatVectorDataPtr uData, ConstFloatVectorDataPtr vData, ConstFloatVectorDataPtr aData )
		:	m_displayWindow( displayWindow ),
			m_tileBound( tileBound ),
			m_uData( uData ),
			m_vData( vData ),
			m_aData( aData ),
			m_u( uData->readable() ),
			m_v( vData->readable() ),
			m_a( aData->readable() )
	{
		V2i oP;
		for( oP.y = validTileBound.min.y; oP.y < validTileBound.max.y; ++oP.y )
		{
			size_t i = index( V2i( validTileBound.min.x, oP.y ), tileBound );
			for( oP.x = validTileBound.min.x; oP.x < validTileBound.max.x; ++oP.x, ++i )
			{
				if( m_a[i] == 0.0f )
				{
					continue;
				}
				const V2f iP = uvToPixel( V2f( m_u[i], m_v[i] ) );
				m_inputWindow.extendBy( iP );
			}
		}

		m_inputWindow.min -= V2i( 1 );
		m_inputWindow.max += V2i( 1 );
	}
Exemple #2
0
	Engine( const Box2i &displayWindow, const Box2i &tileBound, const Box2i &validTileBound, ConstFloatVectorDataPtr xData, ConstFloatVectorDataPtr yData, ConstFloatVectorDataPtr aData, VectorMode vectorMode, VectorUnits vectorUnits )
		:	m_displayWindow( displayWindow ),
			m_tileBound( tileBound ),
			m_xData( xData ),
			m_yData( yData ),
			m_aData( aData ),
			m_x( xData->readable() ),
			m_y( yData->readable() ),
			m_a( aData->readable() ),
			m_vectorMode( vectorMode ),
			m_vectorUnits( vectorUnits )
	{
	}
Exemple #3
0
    void operator()( const blocked_range2d<size_t>& r ) const
    {
        ContextPtr context = new Context( *m_parentContext );
        const Box2i operationWindow( V2i( r.rows().begin()+m_dataWindow.min.x, r.cols().begin()+m_dataWindow.min.y ), V2i( r.rows().end()+m_dataWindow.min.x-1, r.cols().end()+m_dataWindow.min.y-1 ) );
        V2i minTileOrigin = ImagePlug::tileOrigin( operationWindow.min );
        V2i maxTileOrigin = ImagePlug::tileOrigin( operationWindow.max );
        size_t imageStride = m_dataWindow.size().x + 1;

        for( int tileOriginY = minTileOrigin.y; tileOriginY <= maxTileOrigin.y; tileOriginY += m_tileSize )
        {
            for( int tileOriginX = minTileOrigin.x; tileOriginX <= maxTileOrigin.x; tileOriginX += m_tileSize )
            {
                for( vector<string>::const_iterator it = m_channelNames.begin(), eIt = m_channelNames.end(); it != eIt; it++ )
                {
                    context->set( ImagePlug::channelNameContextName, *it );
                    context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) );
                    Context::Scope scope( context.get() );
                    Box2i tileBound( V2i( tileOriginX, tileOriginY ), V2i( tileOriginX + m_tileSize - 1, tileOriginY + m_tileSize - 1 ) );
                    Box2i b = boxIntersection( tileBound, operationWindow );

                    ConstFloatVectorDataPtr tileData = m_channelDataPlug->getValue();

                    for( int y = b.min.y; y<=b.max.y; y++ )
                    {
                        const float *tilePtr = &(tileData->readable()[0]) + (y - tileOriginY) * m_tileSize + (b.min.x - tileOriginX);
                        float *channelPtr = m_imageChannelData[it-m_channelNames.begin()] + ( m_dataWindow.size().y - ( y - m_dataWindow.min.y ) ) * imageStride + (b.min.x - m_dataWindow.min.x);
                        for( int x = b.min.x; x <= b.max.x; x++ )
                        {
                            *channelPtr++ = *tilePtr++;
                        }
                    }
                }
            }
        }
    }
void ToArnoldShapeConverter::convertRadius( const IECore::Primitive *primitive, AtNode *shape ) const
{
	ConstFloatVectorDataPtr radius = primitive->variableData<FloatVectorData>( "radius" );
	if( !radius )
	{
		FloatVectorDataPtr calculatedRadius = new FloatVectorData();
		if( const FloatData *constantRadius = primitive->variableData<FloatData>( "radius", PrimitiveVariable::Constant ) )
		{
			calculatedRadius->writable().push_back( constantRadius->readable() );
		}
		else if( const FloatVectorData *width = primitive->variableData<FloatVectorData>( "width" ) )
		{
			calculatedRadius->writable().resize( width->readable().size() );
			const std::vector<float>::iterator end = calculatedRadius->writable().end();
			std::vector<float>::const_iterator wIt = width->readable().begin();
			for( std::vector<float>::iterator it = calculatedRadius->writable().begin(); it != end; it++, wIt++ )
			{
				*it = *wIt / 2.0f;
			}
		}
		else
		{
			const FloatData *constantWidth = primitive->variableData<FloatData>( "width", PrimitiveVariable::Constant );
			if( !constantWidth )
			{
				constantWidth = primitive->variableData<FloatData>( "constantwidth", PrimitiveVariable::Constant );
			}
			float r = constantWidth ? constantWidth->readable() / 2.0f : 0.5f;
			calculatedRadius->writable().push_back( r );
		}
		radius = calculatedRadius;
	}
	
	AiNodeSetArray(
		shape,
		"radius",
		AiArrayConvert( radius->readable().size(), 1, AI_TYPE_FLOAT, (void *)&( radius->readable()[0] ) )
	);
}
Exemple #5
0
IECore::ConstFloatVectorDataPtr CopyChannels::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	ConstCompoundObjectPtr mapping;
	{
		ImagePlug::GlobalScope c( context );
		mapping = mappingPlug()->getValue();
	}
	if( const IntData *i = mapping->member<const IntData>( channelName ) )
	{
		const ImagePlug *inputImage = inPlugs()->getChild<ImagePlug>( i->readable() );
		const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName );
		const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );
		Box2i inputDataWindow;
		{
			ImagePlug::GlobalScope c( context );
			inputDataWindow = inputImage->dataWindowPlug()->getValue();
		}
		const Box2i validBound = BufferAlgo::intersection( tileBound, inputDataWindow );
		if( validBound == tileBound )
		{
			return inputImage->channelDataPlug()->getValue();
		}
		else
		{
			FloatVectorDataPtr resultData = new FloatVectorData;
			vector<float> &result = resultData->writable();
			result.resize( ImagePlug::tileSize() * ImagePlug::tileSize(), 0.0f );
			if( !BufferAlgo::empty( validBound ) )
			{
				ConstFloatVectorDataPtr inputData = inputImage->channelDataPlug()->getValue();
				copyRegion(
					&inputData->readable().front(),
					tileBound,
					validBound,
					&result.front(),
					tileBound,
					validBound.min
				);
			}
			return resultData;
		}
	}
	else
	{
		return ImagePlug::blackTile();
	}
}
Exemple #6
0
void Unpremultiply::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channel, FloatVectorDataPtr outData ) const
{
	std::string alphaChannel = alphaChannelPlug()->getValue();

	if ( channel == alphaChannel )
	{
		return;
	}

	ConstStringVectorDataPtr inChannelNamesPtr;
	{
		ImagePlug::GlobalScope c( context );
		inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
	}

	const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable();
	if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() )
	{
		std::ostringstream channelError;
		channelError << "Channel '" << alphaChannel << "' does not exist";
		throw( IECore::Exception( channelError.str() ) );
	}

	ImagePlug::ChannelDataScope channelDataScope( context );
	channelDataScope.setChannelName( alphaChannel );

	ConstFloatVectorDataPtr aData = inPlug()->channelDataPlug()->getValue();
	const std::vector<float> &a = aData->readable();
	std::vector<float> &out = outData->writable();

	std::vector<float>::const_iterator aIt = a.begin();
	for ( std::vector<float>::iterator outIt = out.begin(), outItEnd = out.end(); outIt != outItEnd; ++outIt, ++aIt )
	{
		if ( *aIt != 0.0f )
		{
			*outIt /= *aIt;
		}
	}
}
Exemple #7
0
		void operator()( const blocked_range3d<size_t>& r ) const
		{
			ContextPtr context = new Context( *m_parentContext, Context::Borrowed );
			Context::Scope scope( context.get() );
			
			const Box2i operationWindow( V2i( r.rows().begin()+m_dataWindow.min.x, r.cols().begin()+m_dataWindow.min.y ), V2i( r.rows().end()+m_dataWindow.min.x-1, r.cols().end()+m_dataWindow.min.y-1 ) );
			V2i minTileOrigin = ImagePlug::tileOrigin( operationWindow.min );
			V2i maxTileOrigin = ImagePlug::tileOrigin( operationWindow.max );
			size_t imageStride = m_dataWindow.size().x + 1;
			
			for( size_t channelIndex = r.pages().begin(); channelIndex < r.pages().end(); ++channelIndex )
			{
				context->set( ImagePlug::channelNameContextName, m_channelNames[channelIndex] );
				float *channelBegin = m_imageChannelData[channelIndex];
				
				for( int tileOriginY = minTileOrigin.y; tileOriginY <= maxTileOrigin.y; tileOriginY += m_tileSize )
				{
					for( int tileOriginX = minTileOrigin.x; tileOriginX <= maxTileOrigin.x; tileOriginX += m_tileSize )
					{
						context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) );
						
						Box2i tileBound( V2i( tileOriginX, tileOriginY ), V2i( tileOriginX + m_tileSize - 1, tileOriginY + m_tileSize - 1 ) );
						Box2i b = boxIntersection( tileBound, operationWindow );
						size_t tileStrideSize = sizeof(float) * ( b.size().x + 1 );
						
						ConstFloatVectorDataPtr tileData = m_channelDataPlug->getValue();
						const float *tileDataBegin = &(tileData->readable()[0]);

						for( int y = b.min.y; y<=b.max.y; y++ )
						{
							const float *tilePtr = tileDataBegin + (y - tileOriginY) * m_tileSize + (b.min.x - tileOriginX);
							float *channelPtr = channelBegin + ( m_dataWindow.size().y - ( y - m_dataWindow.min.y ) ) * imageStride + (b.min.x - m_dataWindow.min.x);
							std::memcpy( channelPtr, tilePtr, tileStrideSize );
						}
					}
				}
			}
		}
SimpleSubsurface::SimpleSubsurface( ConstV3fVectorDataPtr p, ConstColor3fVectorDataPtr c, ConstFloatVectorDataPtr a, const SplinefColor3f &falloff )
{
	m_privateData = boost::shared_ptr<PrivateData>( new PrivateData );
	
	m_privateData->points = p->copy();
	m_privateData->colors = c->copy();
	
	const vector<float> &areas = a->readable();
	vector<Color3f> &colors = m_privateData->colors->writable();
	for( size_t i=0; i<colors.size(); i++ )
	{
		colors[i] *= areas[i];
	}
	
	m_privateData->tree.init( m_privateData->points->readable().begin(), m_privateData->points->readable().end() );

	m_privateData->falloff.init( SplineRemapper( falloff ), 0, 1, 100 );
	
	m_privateData->nodeCentroids.resize( m_privateData->tree.numNodes() );
	m_privateData->nodeColors.resize( m_privateData->tree.numNodes() );
	m_privateData->nodeBounds.resize( m_privateData->tree.numNodes() );
	buildWalk( m_privateData->tree.rootIndex() );
	
}
ObjectPtr EnvMapSHProjector::doOperation( const CompoundObject *operands )
{
	ImagePrimitive * image = runTimeCast< ImagePrimitive, Object >( m_envMapParameter->getValue() );

	if ( image->getDisplayWindow() != image->getDataWindow() )
	{
		throw Exception( "EnvMapSHProjector only works with images that display and data windows match." );
	}

	unsigned bands = m_bandsParameter->getNumericValue();
	unsigned samples = m_samplesParameter->getNumericValue();
	bool rightHandSystem = m_rightHandSystemParameter->getTypedValue();
	bool applyFilter = m_applyFilterParameter->getTypedValue();
	Imath::M44f orientation = m_orientationParameter->getTypedValue();

	int imgWidth = image->getDataWindow().size().x + 1;
	int imgHeight = image->getDataWindow().size().y + 1;

	// create SH projector
	IECore::SHProjectorf projector( samples );
	projector.computeSamples( bands );

	ConstFloatVectorDataPtr redData = image->getChannel< float >( "R" );
	ConstFloatVectorDataPtr greenData = image->getChannel< float >( "G" );
	ConstFloatVectorDataPtr blueData = image->getChannel< float >( "B" );

	if ( !redData || !greenData || !blueData )
	{
		throw Exception( "EnvMap does not have the three colour channels (R,G,B)!" );
	}

	const std::vector<float> &chR = redData->readable();
	const std::vector<float> &chG = greenData->readable();
	const std::vector<float> &chB = blueData->readable();

	// rotate coordinates along X axis so that the image maps Y coordinates to the vertical direction instead of Z.
	Imath::M44f rotX90 = Imath::Eulerf( M_PI * 0.5, 0, 0 ).toMatrix44();

	// \todo: check if the order of multiplication is what we expect...
	orientation = orientation * rotX90;

	EuclideanToSphericalTransform< Imath::V3f, Imath::V2f > euc2sph;
	std::vector< Imath::V3f >::const_iterator cit = projector.euclideanCoordinates().begin();

	SHColor3f sh( bands );
	unsigned int i;
	unsigned actualSamples = projector.euclideanCoordinates().size();
	Imath::V3f systemConversion(1);
	if ( !rightHandSystem )
	{
		systemConversion[2] = -systemConversion[2];
	}

	// image to SH
	for ( i = 0; i < actualSamples; i++, cit++ )
	{
		Imath::V2f phiTheta = euc2sph.transform( ((*cit) * systemConversion) * orientation );
		int ix = (int)(phiTheta.x * (float)imgWidth / ( M_PI * 2 ));
		int iy = (int)(phiTheta.y * (float)imgHeight /  M_PI );
		if ( ix > imgWidth )
			ix = imgWidth;
		if ( iy > imgHeight )
			iy = imgHeight;
		int offset = iy * imgWidth + ix;
		projector( i, Imath::Color3f( chR[ offset ], chG[ offset ], chB[ offset ] ), sh );
	}

	// filter SH
	if ( applyFilter )
	{
		// use author's suggestion for window size.
		IECore::windowingFilter( sh, 2*sh.bands() );
	}

	Color3fVectorDataPtr result = new Color3fVectorData( sh.coefficients() );
	return result;
}
ObjectPtr EnvMapSampler::doOperation( const CompoundObject * operands )
{
	ImagePrimitivePtr image = static_cast<ImagePrimitive *>( imageParameter()->getValue() )->copy();
	Box2i dataWindow = image->getDataWindow();

	// find the rgb channels
	ConstFloatVectorDataPtr redData = image->getChannel<float>( "R" );
	ConstFloatVectorDataPtr greenData = image->getChannel<float>( "G" );
	ConstFloatVectorDataPtr blueData = image->getChannel<float>( "B" );
	if( !(redData && greenData && blueData) )
	{
		throw Exception( "Image does not contain valid RGB float channels." );
	}
	const vector<float> &red = redData->readable();
	const vector<float> &green = greenData->readable();
	const vector<float> &blue = blueData->readable();

	// get a luminance channel
	LuminanceOpPtr luminanceOp = new LuminanceOp();
	luminanceOp->inputParameter()->setValue( image );
	luminanceOp->copyParameter()->getTypedValue() = false;
	luminanceOp->removeColorPrimVarsParameter()->getTypedValue() = false;
	luminanceOp->operate();

	// do the median cut thing to get some samples
	MedianCutSamplerPtr sampler = new MedianCutSampler;
	sampler->imageParameter()->setValue( image );
	sampler->subdivisionDepthParameter()->setNumericValue( subdivisionDepthParameter()->getNumericValue() );
	ConstCompoundObjectPtr samples = boost::static_pointer_cast<CompoundObject>( sampler->operate() );
	const vector<V2f> &centroids = boost::static_pointer_cast<V2fVectorData>( samples->members().find( "centroids" )->second )->readable();
	const vector<Box2i> &areas = boost::static_pointer_cast<Box2iVectorData>( samples->members().find( "areas" )->second )->readable();

	// get light directions and colors from the samples
	V3fVectorDataPtr directionsData = new V3fVectorData;
	Color3fVectorDataPtr colorsData = new Color3fVectorData;
	vector<V3f> &directions = directionsData->writable();
	vector<Color3f> &colors = colorsData->writable();

	float radiansPerPixel = M_PI / (dataWindow.size().y + 1);
	float angleAtTop = ( M_PI - radiansPerPixel ) / 2.0f;

	for( unsigned i=0; i<centroids.size(); i++ )
	{
		const Box2i &area = areas[i];
		Color3f color( 0 );
		for( int y=area.min.y; y<=area.max.y; y++ )
		{
			int yRel = y - dataWindow.min.y;

			float angle = angleAtTop - yRel * radiansPerPixel;
			float weight = cosf( angle );
			int index = (area.min.x - dataWindow.min.x) + (dataWindow.size().x + 1 ) * yRel;
			for( int x=area.min.x; x<=area.max.x; x++ )
			{
				color[0] += weight * red[index];
				color[1] += weight * green[index];
				color[2] += weight * blue[index];
				index++;
			}
		}
		color /= red.size();
		colors.push_back( color );

		float phi = angleAtTop - (centroids[i].y - dataWindow.min.y) * radiansPerPixel;

		V3f direction;
		direction.y = sinf( phi );
		float r = cosf( phi );
		float theta = 2 * M_PI * lerpfactor( (float)centroids[i].x, (float)dataWindow.min.x, (float)dataWindow.max.x );
		direction.x = r * cosf( theta );
		direction.z = r * sinf( theta );

		directions.push_back( -direction ); // negated so we output the direction the light shines in
	}

	// return the result
	CompoundObjectPtr result = new CompoundObject;
	result->members()["directions"] = directionsData;
	result->members()["colors"] = colorsData;
	return result;
}
Exemple #11
0
IECore::ConstFloatVectorDataPtr Merge::merge( F f, const std::string &channelName, const Imath::V2i &tileOrigin ) const
{
	FloatVectorDataPtr resultData = NULL;
	// Temporary buffer for computing the alpha of intermediate composited layers.
	FloatVectorDataPtr resultAlphaData = NULL;

	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );

	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it )
	{
		if( !(*it)->getInput<ValuePlug>() )
		{
			continue;
		}

		IECore::ConstStringVectorDataPtr channelNamesData = (*it)->channelNamesPlug()->getValue();
		const std::vector<std::string> &channelNames = channelNamesData->readable();

		ConstFloatVectorDataPtr channelData;
		ConstFloatVectorDataPtr alphaData;

		if( channelExists( channelNames, channelName ) )
		{
			channelData = (*it)->channelDataPlug()->getValue();
		}
		else
		{
			channelData = ImagePlug::blackTile();
		}

		if( channelExists( channelNames, "A" ) )
		{
			alphaData = (*it)->channelData( "A", tileOrigin );
		}
		else
		{
			alphaData = ImagePlug::blackTile();
		}

		const Box2i validBound = boxIntersection( tileBound, (*it)->dataWindowPlug()->getValue() );

		if( !resultData )
		{
			// The first connected layer, with which we must initialise our result.
			// There's no guarantee that this layer actually covers the full data
			// window though (the data window could have been expanded by the upper
			// layers) so we must take care to mask out any invalid areas of the input.
			/// \todo I'm not convinced this is correct - if we have no connection
			/// to in[0] then should that not be treated as being a black image, so
			/// we should unconditionally initaliase with in[0] and then always use
			/// the operation for in[1:], even if in[0] is disconnected. In other
			/// words, shouldn't multiplying a white constant over an unconnected
			/// in[0] produce black?
			resultData = channelData->copy();
			resultAlphaData = alphaData->copy();
			float *B = &resultData->writable().front();
			float *b = &resultAlphaData->writable().front();
			for( int y = tileBound.min.y; y < tileBound.max.y; ++y )
			{
				const bool yValid = y >= validBound.min.y && y < validBound.max.y;
				for( int x = tileBound.min.x; x < tileBound.max.x; ++x )
				{
					if( !yValid || x < validBound.min.x || x >= validBound.max.x )
					{
						*B = *b = 0.0f;
					}
					++B; ++b;
				}
			}
		}
		else
		{
			// A higher layer (A) which must be composited over the result (B).
			const float *A = &channelData->readable().front();
			float *B = &resultData->writable().front();
			const float *a = &alphaData->readable().front();
			float *b = &resultAlphaData->writable().front();

			for( int y = tileBound.min.y; y < tileBound.max.y; ++y )
			{
				const bool yValid = y >= validBound.min.y && y < validBound.max.y;
				for( int x = tileBound.min.x; x < tileBound.max.x; ++x )
				{
					const bool valid = yValid && x >= validBound.min.x && x < validBound.max.x;

					*B = f( valid ? *A : 0.0f, *B, valid ? *a : 0.0f, *b );
					*b = f( valid ? *a : 0.0f, *b, valid ? *a : 0.0f, *b );

					++A; ++B; ++a; ++b;
				}
			}
		}
	}

	return resultData;
}
void FaceAreaOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundObject * operands )
{
	string areaPrimVarName = parameters()->parameter<StringParameter>( "areaPrimVar" )->getTypedValue();
	if( areaPrimVarName!="" )
	{
	
		const string &pName = parameters()->parameter<StringParameter>( "pointPrimVar" )->getTypedValue();
		ConstV3fVectorDataPtr pData = mesh->variableData<V3fVectorData>( pName, PrimitiveVariable::Vertex );
		if( !pData )
		{
			throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no \"%s\" primitive variable." ) % pName ) );
		}
		const vector<V3f> &p = pData->readable();

		FloatVectorDataPtr areasData = new FloatVectorData;
		vector<float> &areas = areasData->writable();
		areas.reserve( mesh->variableSize( PrimitiveVariable::Uniform ) );
		PolygonIterator faceEnd = mesh->faceEnd();
		for( PolygonIterator pIt = mesh->faceBegin(); pIt!=faceEnd; pIt++ )
		{
			typedef vector<V3f> PointVector;
			areas.push_back( polygonArea( pIt.vertexBegin( p.begin() ), pIt.vertexEnd( p.begin() ) ) );
		}

		mesh->variables[areaPrimVarName] = PrimitiveVariable( PrimitiveVariable::Uniform, areasData );
	}
	
	string textureAreaPrimVarName = parameters()->parameter<StringParameter>( "textureAreaPrimVar" )->getTypedValue();
	if( textureAreaPrimVarName!="" )
	{
	
		const string &sName = parameters()->parameter<StringParameter>( "sPrimVar" )->getTypedValue();
		PrimitiveVariable::Interpolation sInterpolation = PrimitiveVariable::Vertex;
		ConstFloatVectorDataPtr sData = mesh->variableData<FloatVectorData>( sName, PrimitiveVariable::Vertex );
		if( !sData )
		{
			sData = mesh->variableData<FloatVectorData>( sName, PrimitiveVariable::FaceVarying );
			if( !sData )
			{
				throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no suitable \"%s\" primitive variable." ) % sName ) );
			}
			sInterpolation = PrimitiveVariable::FaceVarying;
		}
		const vector<float> &s = sData->readable();

		const string &tName = parameters()->parameter<StringParameter>( "tPrimVar" )->getTypedValue();
		PrimitiveVariable::Interpolation tInterpolation = PrimitiveVariable::Vertex;
		ConstFloatVectorDataPtr tData = mesh->variableData<FloatVectorData>( tName, PrimitiveVariable::Vertex );
		if( !tData )
		{
			tData = mesh->variableData<FloatVectorData>( tName, PrimitiveVariable::FaceVarying );
			if( !tData )
			{
				throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no suitable \"%s\" primitive variable." ) % tName ) );
			}
			tInterpolation = PrimitiveVariable::FaceVarying;
		}
		const vector<float> &t = tData->readable();

		if( sInterpolation!=tInterpolation )
		{
			throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : interpolation for \"%s\" and \"%s\" primitive variables don't match." ) % sName % tName ) );
		}

		FloatVectorDataPtr textureAreasData = new FloatVectorData;
		vector<float> &textureAreas = textureAreasData->writable();
		textureAreas.reserve( mesh->variableSize( PrimitiveVariable::Uniform ) );
		PolygonIterator faceEnd = mesh->faceEnd();
		for( PolygonIterator pIt = mesh->faceBegin(); pIt!=faceEnd; pIt++ )
		{
			if( sInterpolation==PrimitiveVariable::Vertex )
			{
				typedef PolygonVertexIterator<vector<float>::const_iterator> VertexIterator;
				typedef boost::tuple<VertexIterator, VertexIterator> IteratorTuple;
				typedef boost::zip_iterator<IteratorTuple> ZipIterator;
				typedef boost::transform_iterator<STTupleToV3f, ZipIterator> STIterator;
			
				STIterator begin( ZipIterator( IteratorTuple( pIt.vertexBegin( s.begin() ), pIt.vertexBegin( t.begin() ) ) ) );
				STIterator end( ZipIterator( IteratorTuple( pIt.vertexEnd( s.begin() ), pIt.vertexEnd( t.begin() ) ) ) );
			
				textureAreas.push_back( polygonArea( begin, end ) );
			}
			else
			{
				assert( sInterpolation==PrimitiveVariable::FaceVarying );
				typedef boost::tuple<vector<float>::const_iterator, vector<float>::const_iterator> IteratorTuple;
				typedef boost::zip_iterator<IteratorTuple> ZipIterator;
				typedef boost::transform_iterator<STTupleToV3f, ZipIterator> STIterator;
			
				STIterator begin( ZipIterator( IteratorTuple( pIt.faceVaryingBegin( s.begin() ), pIt.faceVaryingBegin( t.begin() ) ) ) );
				STIterator end( ZipIterator( IteratorTuple( pIt.faceVaryingEnd( s.begin() ), pIt.faceVaryingEnd( t.begin() ) ) ) );
			
				textureAreas.push_back( polygonArea( begin, end ) );
			}
		}

		mesh->variables[textureAreaPrimVarName] = PrimitiveVariable( PrimitiveVariable::Uniform, textureAreasData );
	
	}
	
}
void NURBSPrimitive::setTopology(  int uOrder, ConstFloatVectorDataPtr uKnot, float uMin, float uMax,
	int vOrder, ConstFloatVectorDataPtr vKnot, float vMin, float vMax )
{
	// check order isn't too small
	if( uOrder<2 )
	{
		throw Exception( "Order in u direction too small." );
	}
	if( vOrder<2 )
	{
		throw Exception( "Order in v direction too small." );
	}

	// check knots have enough entries for the order.
	// an order of N demands at least N control points
	// and numKnots==numControlPoints + order
	// so we need numKnots>=2*order
	if( (int)uKnot->readable().size() < uOrder * 2 )
	{
		throw Exception( "Not enough knot values in u direction." );
	}
	if( (int)vKnot->readable().size() < vOrder * 2 )
	{
		throw Exception( "Not enough knot values in v direction." );
	}

	// check knots are monotonically increasing
	const vector<float> &u = uKnot->readable();
	float previous = u[0];
	for( unsigned int i=0; i<u.size(); i++ )
	{
		if( u[i]<previous )
		{
			throw Exception( "Knots not monotonically increasing in u direction." );
		}
		previous = u[i];
	}
	const vector<float> &v = vKnot->readable();
	previous = v[0];
	for( unsigned int i=0; i<v.size(); i++ )
	{
		if( v[i]<previous )
		{
			throw Exception( "Knots not monotonically increasing in v direction." );
		}
		previous = v[i];
	}

	// check min and max parametric values are in range
	if( uMin > uMax )
	{
		throw Exception( "uMin greater than uMax." );
	}
	if( vMin > vMax )
	{
		throw Exception( "vMin greater than vMax." );
	}

	if( uMin < u[uOrder-2] )
	{
		throw Exception( "uMin too small." );
	}
	if( uMax > u[u.size()-uOrder+1] )
	{
		throw Exception( "uMax too great." );
	}

	if( vMin < v[vOrder-2] )
	{
		throw Exception( "vMin too small." );
	}
	if( vMax > v[v.size()-vOrder+1] )
	{
		throw Exception( "vMax too great." );
	}

	// set everything (taking copies of the data)

	m_uOrder = uOrder;
	m_uKnot = uKnot->copy();
	m_uMin = uMin;
	m_uMax = uMax;
	m_vOrder = vOrder;
	m_vKnot = vKnot->copy();
	m_vMin = vMin;
	m_vMax = vMax;
}
Exemple #14
0
IECore::ConstFloatVectorDataPtr Mix::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{

	const float mix = mixPlug()->getValue();

	if( mix == 0.0f )
	{
		return inPlugs()->getChild< ImagePlug>( 0 )->channelDataPlug()->getValue();
	}
	else if( mix == 1.0f && !maskPlug()->getInput<ValuePlug>() )
	{
		return inPlugs()->getChild< ImagePlug >( 1 )->channelDataPlug()->getValue();
	}

	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );

	IECore::ConstStringVectorDataPtr maskChannelNamesData;
	Box2i maskDataWindow;
	{
		ImagePlug::GlobalScope c( Context::current() );
		maskChannelNamesData = maskPlug()->channelNamesPlug()->getValue();
		maskDataWindow = maskPlug()->dataWindowPlug()->getValue();
	}

	const std::string &maskChannel = maskChannelPlug()->getValue();
	ConstFloatVectorDataPtr maskData = NULL;
	Box2i maskValidBound;
	if( maskPlug()->getInput<ValuePlug>() && ImageAlgo::channelExists( maskChannelNamesData->readable(), maskChannel ) )
	{
		maskData = maskPlug()->channelData( maskChannel, tileOrigin );
		maskValidBound = boxIntersection( tileBound, maskDataWindow );
	}

	ConstFloatVectorDataPtr channelData[2];
	Box2i validBound[2];

	int i = 0;
	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it,++i )
	{
		IECore::ConstStringVectorDataPtr channelNamesData;
		Box2i dataWindow;
		{
			ImagePlug::GlobalScope c( Context::current() );
			channelNamesData = (*it)->channelNamesPlug()->getValue();
			dataWindow = (*it)->dataWindowPlug()->getValue();
		}

		const std::vector<std::string> &channelNames = channelNamesData->readable();


		if( ImageAlgo::channelExists( channelNames, channelName ) )
		{
			channelData[i] = (*it)->channelDataPlug()->getValue();
			validBound[i] = boxIntersection( tileBound, dataWindow );
		}
		else
		{
			channelData[i] = NULL;
			validBound[i] = Box2i();
		}

	}


	FloatVectorDataPtr resultData = ImagePlug::blackTile()->copy();
	float *R = &resultData->writable().front();
	const float *A = channelData[0] ? &channelData[0]->readable().front() : NULL;
	const float *B = channelData[1] ? &channelData[1]->readable().front() : NULL;
	const float *M = maskData ? &maskData->readable().front() : NULL;

	for( int y = tileBound.min.y; y < tileBound.max.y; ++y )
	{
		const bool yValidIn0 = y >= validBound[0].min.y && y < validBound[0].max.y;
		const bool yValidIn1 = y >= validBound[1].min.y && y < validBound[1].max.y;
		const bool yValidMask = y >= maskValidBound.min.y && y < maskValidBound.max.y;

		for( int x = tileBound.min.x; x < tileBound.max.x; ++x )
		{
			float a = 0;
			if( yValidIn0 && x >= validBound[0].min.x && x < validBound[0].max.x )
			{
				a = *A;
			}

			float b = 0;
			if( yValidIn1 && x >= validBound[1].min.x && x < validBound[1].max.x )
			{
				b = *B;
			}

			float m = mix;
			if( yValidMask && x >= maskValidBound.min.x && x < maskValidBound.max.x )
			{
				m *= std::max( 0.0f, std::min( 1.0f, *M ) );
			}

			*R = a * ( 1 - m ) + b * m;

			++R; ++A; ++B; ++M;
		}
	}

	return resultData;
}
Exemple #15
0
PatchMeshPrimitivePtr CurveExtrudeOp::buildPatchMesh( const CurvesPrimitive * curves, unsigned curveIndex, unsigned vertexOffset, unsigned varyingOffset ) const
{
	if ( curves->periodic() )
	{
		throw InvalidArgumentException( "CurveExtrudeOp: Cannot convert periodic curves" );
	}

	PrimitiveVariableMap::const_iterator it = curves->variables.find( "P" );
	if ( it == curves->variables.end() )
	{
		throw InvalidArgumentException( "CurveExtrudeOp: Input curve has no 'P' primvar" );
	}
	ConstV3fVectorDataPtr pData = runTimeCast< const V3fVectorData >( it->second.data );
	if ( !pData )
	{
		throw InvalidArgumentException( "CurveExtrudeOp: Input curve has no 'P' primvar of type V3fVectorData" );
	}

	float width = 1.0f;
	it = curves->variables.find( "constantwidth" );
	if ( it != curves->variables.end() )
	{
		ConstFloatDataPtr widthData = 0;
		if ( it->second.interpolation == PrimitiveVariable::Constant )
		{
			widthData = runTimeCast< const FloatData >( it->second.data );
		}

		if ( widthData )
		{
			width = widthData->readable();
		}
		else
		{
			msg( Msg::Warning, "CurveExtrudeOp", "Ignoring malformed primvar 'constantwidth'" );
		}
	}

	ConstFloatVectorDataPtr varyingWidthData = 0;
	ConstFloatVectorDataPtr vertexWidthData = 0;
	it = curves->variables.find( "width" );
	if ( it != curves->variables.end() )
	{
		if ( it->second.interpolation == PrimitiveVariable::Varying )
		{
			varyingWidthData = runTimeCast< const FloatVectorData >( it->second.data );
		}
		else if ( it->second.interpolation == PrimitiveVariable::Vertex )
		{
			vertexWidthData = runTimeCast< const FloatVectorData >( it->second.data );
		}

		if ( !varyingWidthData && !vertexWidthData)
		{
			msg( Msg::Warning, "CurveExtrudeOp", "Ignoring malformed primvar 'width'" );
		}
	}

	const V2i &resolution = m_resolutionParameter->getTypedValue();

	const unsigned int vPoints = resolution.y;
	const unsigned int uPoints = resolution.x;

	PatchMeshPrimitivePtr patchMesh = new PatchMeshPrimitive(
		uPoints,
		vPoints + 2, // End points are duplicated
		CubicBasisf::catmullRom(),
		CubicBasisf::catmullRom(),
		true,
		false
	);

	for ( PrimitiveVariableMap::const_iterator it = curves->variables.begin(); it != curves->variables.end(); ++it )
	{
		if ( it->second.interpolation == PrimitiveVariable::FaceVarying || it->second.interpolation == PrimitiveVariable::Varying )
		{
			VaryingFn varyingFn( it->first, curves, curveIndex, varyingOffset, resolution );
 			assert( it->second.data );

			patchMesh->variables[ it->first ] = PrimitiveVariable(
				it->second.interpolation,
				despatchTypedData<VaryingFn, TypeTraits::IsStrictlyInterpolableVectorTypedData>( it->second.data, varyingFn )
			);

		}
		else if ( it->second.interpolation == PrimitiveVariable::Vertex )
		{
			VertexFn vertexFn( it->first, curves, curveIndex, vertexOffset, resolution );
 			assert( it->second.data );

			patchMesh->variables[ it->first ] = PrimitiveVariable(
				it->second.interpolation,
				despatchTypedData<VertexFn, TypeTraits::IsStrictlyInterpolableVectorTypedData>( it->second.data, vertexFn )
			);

		}
		else if ( it->second.interpolation == PrimitiveVariable::Constant )
		{
			patchMesh->variables[ it->first ] = PrimitiveVariable( it->second.interpolation, it->second.data->copy() );
		}
		else if ( it->second.interpolation == PrimitiveVariable::Uniform )
		{
			UniformFn uniformFn( it->first, curves, curveIndex );
			patchMesh->variables[ it->first ] = PrimitiveVariable(
				PrimitiveVariable::Constant,
				despatchTypedData<UniformFn, TypeTraits::IsVectorTypedData>( it->second.data, uniformFn )
			);
		}
	}

	if ( varyingWidthData )
	{
		assert( !vertexWidthData );
		PrimitiveVariableMap::const_iterator it = patchMesh->variables.find( "width" );
		assert( it !=  patchMesh->variables.end() );

		varyingWidthData = runTimeCast< const FloatVectorData >( it->second.data );
		assert( varyingWidthData );
	}
	else if ( vertexWidthData )
	{
		PrimitiveVariableMap::const_iterator it = patchMesh->variables.find( "width" );
		assert( it !=  patchMesh->variables.end() );

		vertexWidthData = runTimeCast< const FloatVectorData >( it->second.data );
		assert( vertexWidthData );
	}

	const V3fVectorData::ValueType &p = pData->readable();

	V3fVectorData::ValueType resampledPoints;
	resampledPoints.reserve( vPoints );

	V3fVectorData::ValueType resampledTangents;
	resampledPoints.reserve( vPoints );

	/// \todo Make adaptive
	for ( unsigned v = 0; v < vPoints; v ++)
	{
		size_t iSeg;
		float fSeg;

		/// Make sure we don't fall off the end of the curve
		if ( v == vPoints - 1 )
		{
			iSeg = curves->numSegments( curveIndex ) - 1;
			fSeg = 1.0f - std::numeric_limits<float>::epsilon();
		}
		else
		{
			float curveParam = float(v) / ( vPoints - 1 );
			fSeg = curveParam * curves->numSegments( curveIndex );
			iSeg = (size_t)floor( fSeg );
			fSeg = fSeg - iSeg;
		}

		size_t segmentStart = iSeg;

		size_t i0 = std::min( segmentStart + 0, curves->variableSize( PrimitiveVariable::Vertex, curveIndex ) );
		size_t i1 = std::min( segmentStart + 1, curves->variableSize( PrimitiveVariable::Vertex, curveIndex ) );
		size_t i2 = std::min( segmentStart + 2, curves->variableSize( PrimitiveVariable::Vertex, curveIndex ) );
		size_t i3 = std::min( segmentStart + 3, curves->variableSize( PrimitiveVariable::Vertex, curveIndex ) );

		const Imath::V3f &p0 = p[ vertexOffset + i0 ];
		const Imath::V3f &p1 = p[ vertexOffset + i1  ];
		const Imath::V3f &p2 = p[ vertexOffset + i2  ];
		const Imath::V3f &p3 = p[ vertexOffset + i3  ];

		Imath::V3f pt = curves->basis()(
				fSeg,
				p0, p1, p2, p3
			);

		resampledPoints.push_back( pt );

		resampledTangents.push_back(
			curves->basis().derivative(
				fSeg,
				p0, p1, p2, p3
			).normalized()
		);

	}
	assert( resampledPoints.size() == vPoints );
	assert( resampledTangents.size() == vPoints );

	std::vector< M44f > frames;

	buildReferenceFrames( resampledPoints, resampledTangents, frames );
	assert( frames.size() == vPoints );

	std::vector< V3f > patchP;
	patchP.reserve( uPoints * ( vPoints + 2 ) );

	for ( unsigned int v = 0; v < vPoints; v++ )
	{
		if ( varyingWidthData )
		{
			assert( !vertexWidthData );
			assert( v * uPoints <  varyingWidthData->readable().size() );
			width = varyingWidthData->readable()[v * uPoints];
		}
		else if ( vertexWidthData )
		{
			assert( (v+1) * uPoints <  vertexWidthData->readable().size() );
			width = vertexWidthData->readable()[(v+1) * uPoints];
		}

		const float radius = width / 2.0f;

		/// Double up end points
		const int num = v == 0 || v == vPoints - 1 ? 2 : 1;

		for ( int x = 0; x < num; x++)
		{
			for( unsigned int u = 0; u < uPoints; u++ )
			{
				/// We're periodic in 'u', so no need to close the curve.
				/// Go from -PI to PI, in order to make the periodicity work, and to give the
				/// surface the correct orientation.
				float theta = -2.0 * M_PI * float(u) / float(uPoints) - M_PI;

				V3f circlePoint(
					0.0,
					radius * cos( theta ),
					radius * sin( theta )
				);

				circlePoint = circlePoint * frames[v];

				patchP.push_back( circlePoint );
			}
		}
	}

	patchMesh->variables["P"] = PrimitiveVariable( PrimitiveVariable::Vertex, new V3fVectorData( patchP ) );

	assert( patchMesh->arePrimitiveVariablesValid() );

	return patchMesh;
}