void FromHoudiniPolygonsConverter::convertCorners( MeshPrimitive *mesh ) const
{
	// Houdini stores corners via a Point Attrib (which has been converted to a Vertex PrimitiveVariable)
	const auto *cornerWeightData = mesh->variableData<FloatVectorData>( g_cornerWeightAttrib, PrimitiveVariable::Vertex );
	if( !cornerWeightData )
	{
		return;
	}

	IntVectorDataPtr cornerIdsData = new IntVectorData();
	auto &cornerIds = cornerIdsData->writable();

	FloatVectorDataPtr cornerSharpnessesData = new FloatVectorData();
	auto &cornerSharpnesses = cornerSharpnessesData->writable();

	const auto &cornerWeights = cornerWeightData->readable();
	for( size_t i = 0; i < cornerWeights.size(); ++i )
	{
		if( cornerWeights[i] > 0.0f )
		{
			cornerIds.push_back( i );
			cornerSharpnesses.push_back( cornerWeights[i] );
		}
	}

	if( !cornerIds.empty() )
	{
		mesh->setCorners( cornerIdsData.get(), cornerSharpnessesData.get() );
		mesh->variables.erase( g_cornerWeightAttrib );
	}
}
void FromHoudiniPolygonsConverter::convertCreases( MeshPrimitive *mesh, const std::vector<int> &vertIds, size_t numEdges ) const
{
	// Houdini stores creases via a Vertex Attrib (which has been converted to a FaceVarying PrimitiveVariable),
	// with the first face-vert of each creased face-edge containing the sharpness, and all other face-verts set to 0.
	const auto *creaseWeightData = mesh->variableData<FloatVectorData>( g_creaseWeightAttrib, PrimitiveVariable::FaceVarying );
	if( !creaseWeightData )
	{
		return;
	}

	IntVectorDataPtr creaseLengthsData = new IntVectorData();
	auto &creaseLengths = creaseLengthsData->writable();

	IntVectorDataPtr creaseIdsData = new IntVectorData();
	auto &creaseIds = creaseIdsData->writable();

	FloatVectorDataPtr creaseSharpnessesData = new FloatVectorData();
	auto &creaseSharpnesses = creaseSharpnessesData->writable();

	// Calculate face-edge offsets based on winding order in Houdini,
	// which is opposite to that of Cortex. We need these to map from
	// single face-vert crease weights and find both verts of the edge.
	size_t faceOffset = 0;
	std::vector<int> windingOffsets;
	// most face-vert offsets will be to use the previous face-vert
	windingOffsets.resize( mesh->variableSize( PrimitiveVariable::FaceVarying ), -1 );
	for( auto numFaceVerts : mesh->verticesPerFace()->readable() )
	{
		// but we need to mark a wraparound vert for each face
		windingOffsets[faceOffset] = (numFaceVerts - 1);
		faceOffset += numFaceVerts;
	}

	const auto &creaseWeights = creaseWeightData->readable();
	for( int i = 0; i < creaseWeights.size(); ++i )
	{
		// there is a crease at this face-edge
		if( creaseWeights[i] > 0.0f )
		{
			// locate the 2nd vert of this face-edge
			int nextFaceVert = i + windingOffsets[i];

			// Since Houdini will have stored the crease in both directions
			// (once for each face-edge), we need to make sure we only record
			// it once, so we enforce that the vertIds are increasing.
			if( vertIds[i] < vertIds[nextFaceVert] )
			{
				creaseLengths.push_back( 2 );
				creaseIds.push_back( vertIds[i] );
				creaseIds.push_back( vertIds[nextFaceVert] );
				creaseSharpnesses.push_back( creaseWeights[i] );
			}
		}
	}

	if( !creaseLengths.empty() )
	{
		mesh->setCreases( creaseLengthsData.get(), creaseIdsData.get(), creaseSharpnessesData.get() );
		mesh->variables.erase( g_creaseWeightAttrib );
	}
}
예제 #3
0
void ImageCompositeOp::composite( CompositeFn fn, DataWindowResult dwr, ImagePrimitive * imageB, const CompoundObject * operands )
{
	assert( fn );
	assert( imageB );
	assert( operands );

	const StringVectorParameter::ValueType &channelNames = channelNamesParameter()->getTypedValue();
	if ( !channelNames.size() )
	{
		throw InvalidArgumentException( "ImageCompositeOp: No channels specified" );
	}

	ImagePrimitivePtr imageA = runTimeCast< ImagePrimitive > ( imageAParameter()->getValue() );
	assert( imageA );

	const std::string &alphaChannel = alphaChannelNameParameter()->getTypedValue();
	if ( !imageA->arePrimitiveVariablesValid() )
	{
		throw InvalidArgumentException( "ImageCompositeOp: Input image has invalid channels" );
	}

	const int inputMode = m_inputModeParameter->getNumericValue();
	if ( inputMode == Unpremultiplied )
	{
		ImagePremultiplyOpPtr premultOp = new ImagePremultiplyOp();
		premultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel );
		premultOp->channelNamesParameter()->setTypedValue( channelNames );

		if ( imageA->variables.find( alphaChannel ) != imageA->variables.end() )
		{
			/// Make a new imageA, premultiplied
			premultOp->copyParameter()->setTypedValue( true );
			premultOp->inputParameter()->setValue( imageA );

			imageA = assertedStaticCast< ImagePrimitive >( premultOp->operate() );
			assert( imageA->arePrimitiveVariablesValid() );
		}

		if ( imageB->variables.find( alphaChannel ) != imageB->variables.end() )
		{
			/// Premultiply imageB in-place
			premultOp->copyParameter()->setTypedValue( false );
			premultOp->inputParameter()->setValue( imageB );
			premultOp->operate();
		}
	}
	else
	{
		assert( inputMode == Premultiplied );
	}


	const Imath::Box2i displayWindow = imageB->getDisplayWindow();

	Imath::Box2i newDataWindow = imageB->getDataWindow();

	if ( dwr == Union )
	{
		newDataWindow.extendBy( imageA->getDataWindow() );
	}
	else
	{
		assert( dwr == Intersection );
		newDataWindow = boxIntersection( newDataWindow, imageA->getDataWindow() );
	}

	newDataWindow = boxIntersection( newDataWindow, displayWindow );

	ImageCropOpPtr cropOp = new ImageCropOp();

	/// Need to make sure that we don't create a new image here - we want to modify the current one in-place. So,
	/// we turn off the "copy" parameter of ModifyOp.
	cropOp->copyParameter()->setTypedValue( false );
	cropOp->inputParameter()->setValue( imageB );
	cropOp->cropBoxParameter()->setTypedValue( newDataWindow );
	cropOp->matchDataWindowParameter()->setTypedValue( true );
	cropOp->resetOriginParameter()->setTypedValue( false );

	cropOp->operate();

	assert( imageB->arePrimitiveVariablesValid() );
	assert( imageB->getDataWindow() == newDataWindow );

	/// \todo Use the "reformat" parameter of the ImageCropOp to do this, when it's implemented
	imageB->setDisplayWindow( displayWindow );

	FloatVectorDataPtr aAlphaData = getChannelData( imageA.get(), alphaChannel, false );
	FloatVectorDataPtr bAlphaData = getChannelData( imageB, alphaChannel, false );

	const int newWidth = newDataWindow.size().x + 1;
	const int newHeight = newDataWindow.size().y + 1;
	const int newArea = newWidth * newHeight;

	assert( newArea == (int)imageB->variableSize( PrimitiveVariable::Vertex ) );

	for( unsigned i=0; i<channelNames.size(); i++ )
	{
		const StringVectorParameter::ValueType::value_type &channelName = channelNames[i];

		FloatVectorDataPtr aData = getChannelData( imageA.get(), channelName );
		assert( aData->readable().size() == imageA->variableSize( PrimitiveVariable::Vertex ) );
		FloatVectorDataPtr bData = getChannelData( imageB, channelName );
		assert( bData->readable().size() == imageB->variableSize( PrimitiveVariable::Vertex ) );
		FloatVectorDataPtr newBData = new FloatVectorData();

		newBData->writable().resize( newArea );
		imageB->variables[ channelName ].data = newBData;

		for ( int y = newDataWindow.min.y; y <= newDataWindow.max.y; y++ )
		{
			int offset = (y - newDataWindow.min.y ) * newWidth;
			for ( int x = newDataWindow.min.x; x <= newDataWindow.max.x; x++, offset++ )
			{
				float aVal = readChannelData( imageA.get(), aData.get(), V2i( x, y ) );
				float bVal = readChannelData( imageB, bData.get(), V2i( x, y ) );

				float aAlpha = aAlphaData ? readChannelData( imageA.get(), aAlphaData.get(), V2i( x, y ) ) : 1.0f;
				float bAlpha = bAlphaData ? readChannelData( imageB, bAlphaData.get(), V2i( x, y ) ) : 1.0f;

				assert( offset >= 0 );
				assert( offset < (int)newBData->readable().size() );
				newBData->writable()[ offset  ] = fn( aVal, aAlpha, bVal, bAlpha );
			}
		}
	}

	/// displayWindow should be unchanged
	assert( imageB->getDisplayWindow() == displayWindow );
	assert( imageB->arePrimitiveVariablesValid() );

	/// If input images were unpremultiplied, then ensure that the output is also
	if ( inputMode == Unpremultiplied && imageB->variables.find( alphaChannel ) != imageB->variables.end() )
	{
		ImageUnpremultiplyOpPtr unpremultOp = new ImageUnpremultiplyOp();
		/// Unpremultiply imageB in-place
		unpremultOp->copyParameter()->setTypedValue( false );
		unpremultOp->channelNamesParameter()->setTypedValue( channelNames );
		unpremultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel );
		unpremultOp->inputParameter()->setValue( imageB );
		unpremultOp->operate();
		assert( imageB->arePrimitiveVariablesValid() );
	}
	else
	{
		assert( inputMode == Premultiplied );
	}
}