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 ); } }
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 ); } }