예제 #1
0
PointsPrimitivePtr mergePoints( const std::vector<const PointsPrimitive *> &pointsPrimitives )
{
	size_t totalPointCount = 0;
	typedef std::map<std::string, IECore::TypeId> FoundPrimvars;
	FoundPrimvars foundPrimvars;

	PrimitiveVariableMap constantPrimVars;

	std::vector<PointsPrimitivePtr> validatedPointsPrimitives( pointsPrimitives.size() );

	// find out which primvars can be merged
	for( size_t i = 0; i < pointsPrimitives.size(); ++i )
	{
		PointsPrimitivePtr pointsPrimitive = validatedPointsPrimitives[i] = pointsPrimitives[i]->copy();

		totalPointCount += pointsPrimitive->getNumPoints();
		PrimitiveVariableMap &variables = pointsPrimitive->variables;
		for( PrimitiveVariableMap::iterator it = variables.begin(); it != variables.end(); ++it )
		{
			DataPtr data = it->second.data;
			const IECore::TypeId typeId = data->typeId();
			PrimitiveVariable::Interpolation interpolation = it->second.interpolation;
			const std::string &name = it->first;

			bool bExistingConstant = constantPrimVars.find( name ) != constantPrimVars.end();
			FoundPrimvars::const_iterator fIt = foundPrimvars.find( name );
			bool bExistingVertex = fIt != foundPrimvars.end();

			if( interpolation == PrimitiveVariable::Constant )
			{
				if( bExistingVertex )
				{
					std::string msg = boost::str( boost::format( "PointsAlgo::mergePoints mismatching primvar %s" ) % name );
					throw InvalidArgumentException( msg );
				}

				if( !bExistingConstant )
				{
					constantPrimVars[name] = it->second;
				}
				continue;
			}

			if( interpolation == PrimitiveVariable::Vertex )
			{

				PrimitiveVariableMap::const_iterator constantPrimVarIt = constantPrimVars.find( name );
				if( constantPrimVarIt != constantPrimVars.end() )
				{
					std::string msg = boost::str( boost::format( "PointsAlgo::mergePoints mismatching primvar %s" ) % name );
					throw InvalidArgumentException( msg );
				}

				if( !bExistingVertex )
				{
					foundPrimvars[name] = typeId;
				}
				else
				{
					if( fIt->second != typeId )
					{
						DataCastOpPtr castOp = new DataCastOp();

						castOp->objectParameter()->setValue( data );
						castOp->targetTypeParameter()->setNumericValue( fIt->second );

						try
						{
							it->second.data = runTimeCast<Data>( castOp->operate() );
						}
						catch( const IECore::Exception &e )
						{
							std::string msg = boost::str( boost::format( "PointsAlgo::mergePoints unable to cast primvar %s (%s) " ) % name % e.what() );
							throw InvalidArgumentException( msg );
						}
					}
				}
			}
		}
	}

	// allocate the new points primitive and copy the primvars
	PointsPrimitivePtr newPoints = new PointsPrimitive( totalPointCount );

	// copy constant primvars
	for( PrimitiveVariableMap::const_iterator it = constantPrimVars.begin(); it != constantPrimVars.end(); ++it )
	{
		newPoints->variables[it->first] = it->second;
	}

	// merge vertex primvars
	for( FoundPrimvars::const_iterator it = foundPrimvars.begin(); it != foundPrimvars.end(); ++it )
	{
		DataPtr mergedData = mergePrimVars( validatedPointsPrimitives, it->first, totalPointCount );
		newPoints->variables[it->first] = PrimitiveVariable( PrimitiveVariable::Vertex, mergedData );
	}

	return newPoints;
}
void ToHoudiniGeometryConverter::transferAttribValues(
	const Primitive *primitive, GU_Detail *geo,
	const GA_Range &points, const GA_Range &prims,
	PrimitiveVariable::Interpolation vertexInterpolation,
	PrimitiveVariable::Interpolation primitiveInterpolation,
	PrimitiveVariable::Interpolation pointInterpolation,
	PrimitiveVariable::Interpolation detailInterpolation
) const
{
	GA_OffsetList offsets;
	if ( prims.isValid() )
	{
		const GA_PrimitiveList &primitives = geo->getPrimitiveList();
		for ( GA_Iterator it=prims.begin(); !it.atEnd(); ++it )
		{
			const GA_Primitive *prim = primitives.get( it.getOffset() );
			size_t numPrimVerts = prim->getVertexCount();
			for ( size_t v=0; v < numPrimVerts; v++ )
			{
				if ( prim->getTypeId() == GEO_PRIMPOLY )
				{
					offsets.append( prim->getVertexOffset( numPrimVerts - 1 - v ) );
				}
				else
				{
					offsets.append( prim->getVertexOffset( v ) );
				}
			}
		}
	}

	GA_Range vertRange( geo->getVertexMap(), offsets );
	
	UT_String filter( attributeFilterParameter()->getTypedValue() );
	
	// match all the string variables to each associated indices variable
	/// \todo: replace all this logic with IECore::IndexedData once it exists...
	PrimitiveVariableMap stringsToIndices;
	for ( PrimitiveVariableMap::const_iterator it=primitive->variables.begin() ; it != primitive->variables.end(); it++ )
	{
		if ( !primitive->isPrimitiveVariableValid( it->second ) )
		{
			IECore::msg( IECore::MessageHandler::Warning, "ToHoudiniGeometryConverter", "PrimitiveVariable " + it->first + " is invalid. Ignoring." );
			filter += UT_String( " ^" + it->first );
			continue;
		}

		ToHoudiniAttribConverterPtr converter = ToHoudiniAttribConverter::create( it->second.data.get() );
		if ( !converter )
		{
			continue;
		}
		
		if ( it->second.data->isInstanceOf( StringVectorDataTypeId ) )
		{
			std::string indicesVariableName = it->first + "Indices";
			PrimitiveVariableMap::const_iterator indices = primitive->variables.find( indicesVariableName );
			if ( indices != primitive->variables.end() && indices->second.data->isInstanceOf( IntVectorDataTypeId ) && primitive->isPrimitiveVariableValid( indices->second ) )
			{
				stringsToIndices[it->first] = indices->second;
				filter += UT_String( " ^" + indicesVariableName );
			}
		}
	}
	
	bool convertStandardAttributes = m_convertStandardAttributesParameter->getTypedValue();
	if ( convertStandardAttributes && UT_String( "s" ).multiMatch( filter ) && UT_String( "t" ).multiMatch( filter ) )
	{
		// convert s and t to uv
		PrimitiveVariableMap::const_iterator sPrimVar = primitive->variables.find( "s" );
		PrimitiveVariableMap::const_iterator tPrimVar = primitive->variables.find( "t" );
		if ( sPrimVar != primitive->variables.end() && tPrimVar != primitive->variables.end() )
		{
			if ( sPrimVar->second.interpolation == tPrimVar->second.interpolation )
			{
				const FloatVectorData *sData = runTimeCast<const FloatVectorData>( sPrimVar->second.data.get() );
				const FloatVectorData *tData = runTimeCast<const FloatVectorData>( tPrimVar->second.data.get() );
				if ( sData && tData )
				{
					const std::vector<float> &s = sData->readable();
					const std::vector<float> &t = tData->readable();
					
					std::vector<Imath::V3f> uvw;
					uvw.reserve( s.size() );
					for ( size_t i=0; i < s.size(); ++i )
					{
						uvw.push_back( Imath::V3f( s[i], 1 - t[i], 0 ) );
					}
					
					GA_Range range = vertRange;
					if ( sPrimVar->second.interpolation == pointInterpolation )
					{
						range = points;
					}
					
					ToHoudiniAttribConverterPtr converter = ToHoudiniAttribConverter::create( new V3fVectorData( uvw ) );
					converter->convert( "uv", geo, range );
					filter += " ^s ^t";
				}
			}
		}
	}
	
 	UT_StringMMPattern attribFilter;
	attribFilter.compile( filter );
	
	// add the primitive variables to the various GEO_AttribDicts based on interpolation type
	for ( PrimitiveVariableMap::const_iterator it=primitive->variables.begin() ; it != primitive->variables.end(); it++ )
	{
		UT_String varName( it->first );
		if ( !varName.multiMatch( attribFilter ) )
		{
			continue;
		}
		
		PrimitiveVariable primVar = processPrimitiveVariable( primitive, it->second );
		ToHoudiniAttribConverterPtr converter = ToHoudiniAttribConverter::create( primVar.data.get() );
		if ( !converter )
		{
			continue;
		}
		
		PrimitiveVariable::Interpolation interpolation = primVar.interpolation;
		
		if ( converter->isInstanceOf( (IECore::TypeId)ToHoudiniStringVectorAttribConverterTypeId ) )
		{
			PrimitiveVariableMap::const_iterator indices = stringsToIndices.find( it->first );
			if ( indices != stringsToIndices.end() )
			{
				ToHoudiniStringVectorAttribConverter *stringVectorConverter = IECore::runTimeCast<ToHoudiniStringVectorAttribConverter>( converter.get() );
				PrimitiveVariable indicesPrimVar = processPrimitiveVariable( primitive, indices->second );
				stringVectorConverter->indicesParameter()->setValidatedValue( indicesPrimVar.data );
				interpolation = indices->second.interpolation;
			}
		}
		
		const std::string name = ( convertStandardAttributes ) ? processPrimitiveVariableName( it->first ) : it->first;
		
		if ( interpolation == detailInterpolation )
 		{
			// add detail attribs
			try
			{
				converter->convert( name, geo );
			}
			catch ( std::exception &e )
			{
				throw IECore::Exception( "PrimitiveVariable \"" + it->first + "\" could not be converted as a Detail Attrib: " + e.what() );
			}
	 	}
		else if ( interpolation == pointInterpolation )
		{
			// add point attribs
			if ( name == "P" )
			{
				// special case for P
				transferP( runTimeCast<const V3fVectorData>( primVar.data.get() ), geo, points );
			}
			else
			{
 				try
				{
					GA_RWAttributeRef attrRef = converter->convert( name, geo, points );
					
					// mark rest as non-transforming so it doesn't get manipulated once inside Houdini
					if ( name == "rest" || name == "Pref" )
					{
						attrRef.getAttribute()->setNonTransforming( true );
					}
				}
				catch ( std::exception &e )
				{
					throw IECore::Exception( "PrimitiveVariable \"" + it->first + "\" could not be converted as a Point Attrib: " + e.what() );
				}
			}
		}
		else if ( interpolation == primitiveInterpolation )
		{
			// add primitive attribs
			try
			{
				converter->convert( name, geo, prims );
			}
			catch ( std::exception &e )
			{
				throw IECore::Exception( "PrimitiveVariable \"" + it->first + "\" could not be converted as a Primitive Attrib: " + e.what() );
			}
		}
		else if ( interpolation == vertexInterpolation )
		{
			// add vertex attribs
			try
			{
				converter->convert( name, geo, vertRange );
			}
			catch ( std::exception &e )
			{
				throw IECore::Exception( "PrimitiveVariable \"" + it->first + "\" could not be converted as a Vertex Attrib: " + e.what() );
			}
		}
	}
	
	// backwards compatibility with older data
	const StringData *nameData = primitive->blindData()->member<StringData>( "name" );
	if ( nameData && prims.isValid() )
	{
		ToHoudiniStringVectorAttribConverter::convertString( "name", nameData->readable(), geo, prims );
	}
}