FromHoudiniGeometryConverter::Convertability FromHoudiniPolygonsConverter::canConvert( const GU_Detail *geo ) { const GA_PrimitiveList &primitives = geo->getPrimitiveList(); for ( GA_Iterator it=geo->getPrimitiveRange().begin(); !it.atEnd(); ++it ) { const GA_Primitive *prim = primitives.get( it.getOffset() ); if ( prim->getTypeId() != GEO_PRIMPOLY ) { return Inapplicable; } } // is there a single named shape? const GEO_AttributeHandle attrHandle = geo->getPrimAttribute( "name" ); if ( attrHandle.isAttributeValid() ) { const GA_ROAttributeRef attrRef( attrHandle.getAttribute() ); if ( geo->getUniqueValueCount( attrRef ) < 2 ) { return Ideal; } } return Suitable; }
FromHoudiniGeometryConverter::Convertability FromHoudiniCurvesConverter::canConvert( const GU_Detail *geo ) { const GA_PrimitiveList &primitives = geo->getPrimitiveList(); unsigned numPrims = geo->getNumPrimitives(); GA_Iterator firstPrim = geo->getPrimitiveRange().begin(); if ( !numPrims || !compatiblePrimitive( primitives.get( firstPrim.getOffset() )->getTypeId() ) ) { return Inapplicable; } const GEO_Curve *firstCurve = (const GEO_Curve*)primitives.get( firstPrim.getOffset() ); bool periodic = firstCurve->isClosed(); unsigned order = firstCurve->getOrder(); for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it ) { const GA_Primitive *prim = primitives.get( it.getOffset() ); if ( !compatiblePrimitive( prim->getTypeId() ) ) { return Inapplicable; } const GEO_Curve *curve = (const GEO_Curve*)prim; if ( curve->getOrder() != order ) { return Inapplicable; } if ( curve->isClosed() != periodic ) { return Inapplicable; } } // is there a single named shape? const GEO_AttributeHandle attrHandle = geo->getPrimAttribute( "name" ); if ( attrHandle.isAttributeValid() ) { const GA_ROAttributeRef attrRef( attrHandle.getAttribute() ); if ( geo->getUniqueValueCount( attrRef ) < 2 ) { return Ideal; } } return Suitable; }
void detail::getStringTableMapping(GEO_AttributeHandle &srcAttrH, GEO_AttributeHandle &destAttrH, detail::stringTableMapping& o_stm) { o_stm.clear(); const GB_Attribute* srcAttr = srcAttrH.getAttribute(); GB_Attribute* destAttr = destAttrH.getAttribute(); if( srcAttr->getType() == GB_ATTRIB_INDEX && destAttr->getType() == GB_ATTRIB_INDEX) { for( int i=0; i<srcAttr->getIndexSize(); ++i) { int destIndex = destAttr->addIndex(srcAttr->getIndex(i)); o_stm.insert(stringTableMapping::value_type(i, destIndex)); } } }
bool GeoAttributeCopier::createHandles(const attrib_copy& copy, GEO_AttributeHandle& hSrc, GEO_AttributeHandle& hDest) { // find source attrib hSrc = copy.m_srcGeo->getAttribute(copy.m_srcDict, copy.m_srcName.c_str()); if(!hSrc.isAttributeValid()) return false; const char* destName_ = copy.m_destName.c_str(); const GB_Attribute* srcAttrib = hSrc.getAttribute(); assert(srcAttrib); // create attrib if it doesn't exist, or does but data type doesn't match bool createAttrib = true; GEO_AttributeHandle hExist = m_destGeo.getAttribute(copy.m_destDict, destName_); if(hExist.isAttributeValid()) { const GB_Attribute* destAttrib = hExist.getAttribute(); assert(destAttrib); createAttrib = (destAttrib->getType() != srcAttrib->getType()); } if(createAttrib) { GB_AttributeRef aref = m_destGeo.addAttribute(destName_, srcAttrib->getSize(), srcAttrib->getType(), srcAttrib->getDefault(), copy.m_destDict); if(!aref.isValid()) return false; } hDest = m_destGeo.getAttribute(copy.m_destDict, destName_); hDest.setSourceMap(hSrc); return true; }
void IECoreMantra::ProceduralPrimitive::addVisibleRenderable( VisibleRenderablePtr renderable ) { ToHoudiniGeometryConverterPtr converter = ToHoudiniGeometryConverter::create( renderable ); if( !converter ) { msg( Msg::Warning, "ProceduralPrimitive::addVisibleRenderable", "converter could not be found" ); return; } GU_Detail *gdp = allocateGeometry(); GU_DetailHandle handle; handle.allocateAndSet( (GU_Detail*)gdp, false ); bool converted = converter->convert( handle ); if ( !converted ) { msg( Msg::Warning, "ProceduralPrimitive::addVisibleRenderable", "converter failed" ); return; } /// \todo ToHoudiniGeometryConverter does not create a Houdini style uv attribute. /// We make one from s and t. This code should probably live in a converter or in an Op that /// remaps IECore conventions to common Houdini ones. MeshPrimitivePtr mesh = runTimeCast<MeshPrimitive> (renderable); if ( mesh ) { gdp->addTextureAttribute( GA_ATTRIB_VERTEX ); GEO_AttributeHandle auv = gdp->getAttribute( GA_ATTRIB_VERTEX, "uv" ); GEO_AttributeHandle as = gdp->getAttribute( GA_ATTRIB_VERTEX, "s" ); GEO_AttributeHandle at = gdp->getAttribute( GA_ATTRIB_VERTEX, "t" ); if ( auv.isAttributeValid() && as.isAttributeValid() && at.isAttributeValid() ) { GA_GBPrimitiveIterator it( *gdp ); GA_Primitive *p = it.getPrimitive(); while ( p ) { for (int i = 0; i < p->getVertexCount(); ++i) { GA_Offset v = p->getVertexOffset(i); as.setVertex(v); at.setVertex(v); auv.setVertex(v); auv.setF( as.getF(0), 0 ); auv.setF( ((at.getF(0) * -1.0f) + 1.0f), 1 ); // wat, t arrives upside down for some reason. auv.setF( 0.0f, 2 ); } ++it; p = it.getPrimitive(); } } } if ( m_renderer->m_motionType == RendererImplementation::Geometry ) { msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:Geometry" ); if ( !m_renderer->m_motionTimes.empty() ) { if ( (size_t)m_renderer->m_motionSize == m_renderer->m_motionTimes.size() ) { openGeometryObject(); } addGeometry(gdp, m_renderer->m_motionTimes.front()); m_renderer->m_motionTimes.pop_front(); if ( m_renderer->m_motionTimes.empty() ) { applySettings(); closeObject(); } } } else if ( m_renderer->m_motionType == RendererImplementation::ConcatTransform || m_renderer->m_motionType == RendererImplementation::SetTransform ) { // It isn't clear that this will give correct results. // ConcatTransform may need to interpolate transform snapshots. msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:Transform" ); openGeometryObject(); addGeometry(gdp, 0.0f); while ( !m_renderer->m_motionTimes.empty() ) { setPreTransform( convert< UT_Matrix4T<float> >(m_renderer->m_motionTransforms.front()), m_renderer->m_motionTimes.front() ); m_renderer->m_motionTimes.pop_front(); m_renderer->m_motionTransforms.pop_front(); } applySettings(); closeObject(); m_renderer->m_motionType = RendererImplementation::Unknown; } else if ( m_renderer->m_motionType == RendererImplementation::Velocity ) { msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:Velocity" ); openGeometryObject(); addGeometry(gdp, 0.0f); addVelocityBlurGeometry(gdp, m_preBlur, m_postBlur); applySettings(); closeObject(); m_renderer->m_motionType = RendererImplementation::Unknown; } else { msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:None" ); openGeometryObject(); addGeometry( gdp, 0.0f ); setPreTransform( convert< UT_Matrix4T<float> >(m_renderer->m_transformStack.top()), 0.0f); applySettings(); closeObject(); } }
Geo2Emp::ErrorCode Geo2Emp::loadMeshShape( const Nb::Body* pBody ) { if (!_gdp) { //If we don't have a GDP for writing data into Houdini, return error. return EC_NULL_WRITE_GDP; } LogInfo() << "=============== Loading mesh shape ===============" << std::endl; const Nb::TriangleShape* pShape; pShape = pBody->queryConstTriangleShape(); if (!pShape) { //NULL mesh shape, so return right now. return EC_NO_TRIANGLE_SHAPE; } //Get access to shapes we need to loading a mesh (point and triangle) const Nb::TriangleShape& triShape = pBody->constTriangleShape(); const Nb::PointShape& ptShape = pBody->constPointShape(); //Retrieve the number of points and channels int64_t size = ptShape.size(); int channelCount = ptShape.channelCount(); //Attribute Lookup Tables std::vector< GEO_AttributeHandle > attribLut; std::vector<GeoAttributeInfo> attribInfo; //houdini types for the naiad channels. GeoAttributeInfo* pInfo; GEO_AttributeHandle attr; std::string attrName; float zero3f[3] = {0,0,0}; float zero1f = 0; int zero3i[3] = {0,0,0}; int zero1i = 0; const void* data; attribLut.clear(); attribInfo.clear(); attribLut.resize( channelCount ); attribInfo.resize( channelCount ); //Prepare for a blind copy of Naiad channels to Houdini attributes. //Iterate over the channels and create the corresponding attributes in the GDP for (int i = 0; i < channelCount; i++) { //std::cout << "channel: " << i << std::endl; const Nb::ChannelCowPtr& chan = ptShape.channel(i); if ( _empAttribMangle.find( chan->name() ) != _empAttribMangle.end() ) attrName = _empAttribMangle[ chan->name() ]; else attrName = chan->name(); LogDebug() << "Processing EMP Channel: " << chan->name() << "; mangled: " << attrName << std::endl; //Determine the attribute type, and store it pInfo = &(attribInfo[ i ]); pInfo->supported = false; pInfo->size = 0; pInfo->use64 = false; switch ( chan->type() ) { case Nb::ValueBase::IntType: LogDebug() << "IntType " << std::endl; pInfo->type = GB_ATTRIB_INT; pInfo->entries = 1; pInfo->size = sizeof(int); pInfo->supported = true; data = &zero1i; break; case Nb::ValueBase::Int64Type: //NOTE: This might need to be handled differently ... just remember this 'hack' pInfo->type = GB_ATTRIB_INT; pInfo->entries = 1; pInfo->size = sizeof(int); pInfo->supported = true; data = &zero1i; break; case Nb::ValueBase::FloatType: LogDebug() << "FloatType " << std::endl; pInfo->type = GB_ATTRIB_FLOAT; pInfo->size = sizeof(float); pInfo->entries = 1; pInfo->supported = true; data = &zero1f; break; case Nb::ValueBase::Vec3fType: LogDebug() << "Vec3fType " << std::endl; pInfo->type = GB_ATTRIB_VECTOR; pInfo->size = sizeof(float); pInfo->entries = 3; pInfo->supported = true; data = &zero3f; break; default: pInfo->supported = false; break; } //If the attribute is not supported, then continue with the next one. if (!pInfo->supported) { LogVerbose() << "Unsupported attribute. Skipping:" << attrName << std::endl; continue; } //Check whether the attribute exists or not attr = _gdp->getPointAttribute( attrName.c_str() ); if ( !attr.isAttributeValid() ) { LogDebug() << "Creating attribute in GDP:" << attrName << std::endl; _gdp->addPointAttrib( attrName.c_str(), pInfo->size * pInfo->entries, pInfo->type, data); attr = _gdp->getPointAttribute( attrName.c_str() ); } //Put the attribute handle in a Lut for easy access later (during transfer) attribLut[i] = attr; } //Get index buffer from the triangle shape const Nb::Buffer3i& bufIndex ( triShape.constBuffer3i("index") ); int64_t indexBufSize = bufIndex.size(); //Before we start adding points to the GDP, just record how many points are already there. int initialPointCount = _gdp->points().entries(); GEO_Point *ppt; //Now, copy all the points into the GDP. for (int ptNum = 0; ptNum < ptShape.size(); ptNum ++) { ppt = _gdp->appendPoint(); //Iterate over the channels in the point shape and copy the data for (int channelIndex = 0; channelIndex < channelCount; channelIndex++) { pInfo = &(attribInfo[ channelIndex ]); //If the attribute is not supported then skip it if (!pInfo->supported) { continue; } attribLut[ channelIndex ].setElement( ppt ); //Transfer supported attributes (this includes the point Position) switch ( pInfo->type ) { case GB_ATTRIB_INT: { const Nb::Buffer1i& channelData = ptShape.constBuffer1i(channelIndex); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setI( channelData(ptNum) ); } break; case GB_ATTRIB_FLOAT: { //TODO: Handle more that 1 entry here, if we ever get something like that ... although I doubt it would happen. const Nb::Buffer1f& channelData( ptShape.constBuffer1f(channelIndex) ); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setF( channelData(ptNum) ); } break; case GB_ATTRIB_VECTOR: { const Nb::Buffer3f& channelData = ptShape.constBuffer3f(channelIndex); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setV3( UT_Vector3( channelData(ptNum)[0], channelData(ptNum)[1], channelData(ptNum)[2] ) ); } break; default: //not yet implemented. continue; break; } } } //Now that all the points are in the GDP, build the triangles GU_PrimPoly *pPrim; for (int tri = 0; tri < indexBufSize; tri++) { pPrim = GU_PrimPoly::build(_gdp, 3, GU_POLY_CLOSED, 0); //Build a closed poly with 3 points, but don't add them to the GDP. //Set the three vertices of the triangle for (int i = 0; i < 3; i++ ) { pPrim->setVertex(i, _gdp->points()[ initialPointCount + bufIndex(tri)[i] ] ); } } return EC_SUCCESS; }
Geo2Emp::ErrorCode Geo2Emp::loadParticleShape( const Nb::Body* pBody ) { if (!_gdp) { //If we don't have a GDP for writing data into Houdini, return error. return EC_NULL_WRITE_GDP; } const Nb::ParticleShape* pShape; LogInfo() << "=============== Loading particle shape ===============" << std::endl; pShape = pBody->queryConstParticleShape(); if (!pShape) { //std::cout << "Received NULL particle shape!" << std::endl; return EC_NO_PARTICLE_SHAPE; } //Attribute Lookup Tables std::vector< GEO_AttributeHandle > attribLut; std::vector<GeoAttributeInfo> attribInfo; //houdini types for the naiad channels. GeoAttributeInfo* pInfo; std::string attrName; //We have a valid particle shape. Start copying particle data over to the GDP int64_t size = pShape->size(); int channelCount = pShape->channelCount(); GEO_Point *ppt; GEO_AttributeHandle attr; GU_PrimParticle *pParticle; std::vector<std::string> houdiniNames; //houdini names that correspond to naiad channels. std::vector<GB_AttribType> houdiniTypes; //houdini types for the naiad channels. //Default values for attributes float zero3f[3] = {0,0,0}; float zero1f = 0; //int zero3i[3] = {0,0,0}; int zero1i = 0; const void* data; LogVerbose() << "Particle shape size: " << size << std::endl; LogVerbose() << "Particle shape channel count: " << channelCount << std::endl; LogVerbose() << "Building particle primitive..."; pParticle = GU_PrimParticle::build(_gdp, 0); LogVerbose() << "done." << std::endl; attribLut.clear(); attribInfo.clear(); attribLut.resize( channelCount ); attribInfo.resize( channelCount ); //Prepare for a blind copy of Naiad channels to Houdini attributes. //Iterate over the channels and create the corresponding attributes in the GDP for (int i = 0; i < channelCount; i++) { //std::cout << "channel: " << i << std::endl; const Nb::ChannelCowPtr& chan = pShape->channel(i); if ( _empAttribMangle.find( chan->name() ) != _empAttribMangle.end() ) attrName = _empAttribMangle[ chan->name() ]; else attrName = chan->name(); LogDebug() << "Processing EMP Channel: " << chan->name() << "; mangled: " << attrName << std::endl; //Determine the attribute type, and store it pInfo = &(attribInfo[ i ]); pInfo->supported = false; pInfo->size = 0; pInfo->use64 = false; if (attrName.compare("P") == 0) //Don't treat position as an attribute. This needs to be handled separately. continue; switch ( chan->type() ) { case Nb::ValueBase::IntType: pInfo->type = GB_ATTRIB_INT; pInfo->entries = 1; pInfo->size = sizeof(int); pInfo->supported = true; data = &zero1i; break; case Nb::ValueBase::Int64Type: //NOTE: This might need to be handled differently ... just remember this 'hack' pInfo->type = GB_ATTRIB_INT; pInfo->entries = 1; pInfo->size = sizeof(int); pInfo->supported = true; pInfo->use64 = true; data = &zero1i; break; case Nb::ValueBase::FloatType: pInfo->type = GB_ATTRIB_FLOAT; pInfo->size = sizeof(float); pInfo->entries = 1; pInfo->supported = true; data = &zero1f; break; case Nb::ValueBase::Vec3fType: pInfo->type = GB_ATTRIB_VECTOR; pInfo->size = sizeof(float); pInfo->entries = 3; pInfo->supported = true; data = &zero3f; break; default: pInfo->supported = false; break; } //If the attribute is not supported, then continue with the next one. if (!pInfo->supported) { LogVerbose() << "Unsupported attribute. Skipping:" << attrName << std::endl; continue; } //Check whether the attribute exists or not attr = _gdp->getPointAttribute( attrName.c_str() ); if ( !attr.isAttributeValid() ) { LogVerbose() << "Creating attribute in GDP:" << attrName << std::endl; LogDebug() << "Name: " << attrName << std::endl << "Entries: " << pInfo->entries << std::endl << "Size: " << pInfo->size << std::endl; _gdp->addPointAttrib( attrName.c_str(), pInfo->size * pInfo->entries, pInfo->type, data); attr = _gdp->getPointAttribute( attrName.c_str() ); } //Put the attribute handle in a Lut for easy access later. attribLut[i] = attr; } //The channel values for particle shapes are stored in blocks/tiles. unsigned int absPtNum = 0; //Get the block array for the positions channel const em::block3_array3f& positionBlocks( pShape->constBlocks3f("position") ); unsigned int numBlocks = positionBlocks.block_count(); unsigned int bsize; float dec_accumulator = 0.0f; float dec = (1.0f - (_decimation)/100.0f); LogInfo() << "Keeping decimation value: " << dec << std::endl; for (int blockIndex = 0; blockIndex < numBlocks; blockIndex ++) { //if (ptNum % 100 == 0) //Get a single block from the position blocks const em::block3vec3f& posBlock = positionBlocks(blockIndex); if ( blockIndex % 100 == 0 ) LogDebug() << "Block: " << blockIndex << "/" << numBlocks << std::endl; //Iterate over all the points/particles in the position block bsize = posBlock.size(); //Only process the point if the decimation accumulator is greater than one. for (int ptNum = 0; ptNum < bsize; ptNum++, absPtNum++) { dec_accumulator += dec; if (dec_accumulator < 1.0f) //Skip this point continue; //Process this point, remove the dec_accumulator rollover. dec_accumulator -= (int) dec_accumulator; ppt = _gdp->appendPoint(); pParticle->appendParticle(ppt); ppt->setPos( UT_Vector3( posBlock(ptNum)[0], posBlock(ptNum)[1], posBlock(ptNum)[2] ) ); //Loop over the channels and add the attributes //This loop needs to be as fast as possible. for (int channelIndex = 0; channelIndex < channelCount; channelIndex++) { pInfo = &(attribInfo[ channelIndex ]); //If the attribute is not supported then skip it if (!pInfo->supported) { continue; } attribLut[ channelIndex ].setElement( ppt ); switch ( pInfo->type ) { case GB_ATTRIB_INT: { if (pInfo->use64) { const em::block3i64& channelData( pShape->constBlocks1i64(channelIndex)(blockIndex) ); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setI( channelData(ptNum) ); } else { const em::block3i& channelData( pShape->constBlocks1i(channelIndex)(blockIndex) ); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setI( channelData(ptNum) ); } } break; case GB_ATTRIB_FLOAT: { //TODO: Handle more that 1 entry here, if we ever get something like that ... although I doubt it would happen. const em::block3f& channelData( pShape->constBlocks1f(channelIndex)(blockIndex) ); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setF( channelData(ptNum) ); } break; case GB_ATTRIB_VECTOR: { const em::block3vec3f& channelData( pShape->constBlocks3f(channelIndex)(blockIndex) ); //Get the Houdini point attribute using the name list we built earlier. attribLut[channelIndex].setV3( UT_Vector3( channelData(ptNum)[0], channelData(ptNum)[1], channelData(ptNum)[2] ) ); } break; default: //not yet implemented. continue; break; } } } } //std::cout << "all done. " << std::endl; return EC_SUCCESS; }
FromHoudiniGeometryConverter::Convertability FromHoudiniGroupConverter::canConvert( const GU_Detail *geo ) { const GA_PrimitiveList &primitives = geo->getPrimitiveList(); // are there multiple primitives? unsigned numPrims = geo->getNumPrimitives(); if ( numPrims < 2 ) { return Admissible; } // are there mixed primitive types? GA_Iterator firstPrim = geo->getPrimitiveRange().begin(); GA_PrimitiveTypeId firstPrimId = primitives.get( firstPrim.getOffset() )->getTypeId(); for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it ) { if ( primitives.get( it.getOffset() )->getTypeId() != firstPrimId ) { return Ideal; } } // are there multiple named shapes? const GEO_AttributeHandle attrHandle = geo->getPrimAttribute( "name" ); if ( attrHandle.isAttributeValid() ) { const GA_ROAttributeRef attrRef( attrHandle.getAttribute() ); if ( geo->getUniqueValueCount( attrRef ) > 1 ) { return Ideal; } } // are the primitives split into groups? UT_PtrArray<const GA_ElementGroup*> primGroups; geo->getElementGroupList( GA_ATTRIB_PRIMITIVE, primGroups ); if ( primGroups.isEmpty() ) { return Admissible; } bool externalGroups = false; for ( unsigned i=0; i < primGroups.entries(); ++i ) { const GA_ElementGroup *group = primGroups[i]; if ( group->getInternal() ) { continue; } if ( group->entries() == numPrims ) { return Admissible; } externalGroups = true; } if ( externalGroups ) { return Ideal; } return Admissible; }
Geo2Emp::ErrorCode Geo2Emp::saveParticleShape(Nb::Body*& pParticleBody) { if (!_gdp) { //If we don't have a GDP for writing data into Houdini, return error. return EC_NULL_READ_GDP; } LogInfo() << " ************** Saving Particle Shape ************** " << std::endl; pParticleBody = Nb::Factory::createBody("Particle", _bodyName); //get the mutable shapes for the mesh body. Nb::ParticleShape& particleShape( pParticleBody->mutableParticleShape() ); Nb::TileLayout& layout( pParticleBody->mutableLayout() ); layout.worldBoxRefine( em::vec3f(0,0,0), em::vec3f(1,1,1),1,false); //Maps houdini attributes to some cached data GEO_AttributeHandleList attribList; GEO_AttributeHandle* pAttr; const GEO_PointList& ptlist = _gdp->points(); int numpoints = ptlist.entries(); GB_Attribute* pBaseAttr; std::map<int, AttributeInfo> attrLut; AttributeInfo* pAttrInfo; int attrSize; int numAttribs; const GEO_PointAttribDict *pPtAttrDict; attribList.bindDetail(_gdp); //Add all the GDP point attributes to the attribute list attribList.appendAllAttributes( GEO_POINT_DICT ); numAttribs = attribList.entries(); LogVerbose() << "Number of hou attributes: " << attribList.entries() << " empty:" << attribList.isEmpty() << std::endl; for (int i = 0; i < numAttribs; i++) { pAttr = attribList[i]; pAttrInfo = &( attrLut[i] ); pAttrInfo->entries = pAttr->entries(); LogDebug() << "pAttr: " << pAttr << " - " << std::endl; LogDebug() << "Attribute #" << i << " - " << pAttr->getName() << " [size] " << attrSize << std::endl; //Note: if attribute overrides need to be done, this is probably the place. //The attribute creation code *might* need to be moved to another function...or at least some of it //so that it may be shared by other conversion code if ( pAttr->isP() ) { //If we have position, then set up the type manually LogDebug() << "We have a position attribute. Set attributes manually." << std::endl; pAttrInfo->entries = 3; pAttrInfo->type = GB_ATTRIB_VECTOR; } else { //Retrieve attribute info through the standard channels... LogDebug() << "Retrieving attribute data using the Point Dictionary." << std::endl; //Now that we now which attribute we want, find it using the GU_Detail object. //TODO: Is there some beter way of doing this??? pPtAttrDict = dynamic_cast< const GEO_PointAttribDict* >( _gdp->getAttributeDict( GEO_POINT_DICT ) ); pBaseAttr = _gdp->getAttributeDict( GEO_POINT_DICT )->find( pAttr->getName() ); pAttrInfo->type = pBaseAttr->getType(); } LogDebug() << "Switching on attribute type." << std::endl; } //This preprocessor defition was placed here simply because it is only applicable to this code section //and will fail to work anywhere else. Not to be classified under "best coding practices". #define PROCESSCHANNEL_PARTICLE(type1, type2, defaults) \ { \ particleShape.guaranteeChannel ## type1 (empAttrName); \ pAttrInfo->empIndex = particleShape.channelIndex( empAttrName ); \ em::block3_array ## type1 &vectorBlocks( particleShape.mutableBlocks ## type1 ( empAttrName ) ); \ em::block3 ## type2 &vectorData( vectorBlocks(0) ); \ vectorData.reserve( _gdp->points().entries() ); \ pAttrInfo->supported = true; \ } //Iterate over the BGEO attributes and create corresponding channels in the EMP body //Also, store the channel index for direct lookups when transferring data. for (int i = 0; i < numAttribs; i++) { //Mangle the geo attribute name right now pAttr = attribList[i]; std::string empAttrName; if ( _geoAttribMangle.find( pAttr->getName() ) != _geoAttribMangle.end() ) empAttrName = _geoAttribMangle[ pAttr->getName() ]; else empAttrName = pAttr->getName(); LogDebug() << "Mangling name: " << pAttr->getName() << " ==> " << empAttrName << std::endl; pAttrInfo = &( attrLut[i] ); pAttrInfo->supported = false; pAttrInfo->flipvector = true; //By default, flip vectors if ( std::string(pAttr->getName()).compare("P") == 0 ) { pAttrInfo->flipvector = false; } pAttrInfo->empIndex = -1; switch ( pAttrInfo->type ) { case GB_ATTRIB_FLOAT: LogDebug() << "Float " << pAttrInfo->entries << std::endl; switch ( pAttrInfo->entries ) { case 1: PROCESSCHANNEL_PARTICLE( 1f, f, 0.0f ); break; case 3: PROCESSCHANNEL_PARTICLE( 3f, vec3f, em::vec3f(0.0f) ); break; } break; case GB_ATTRIB_INT: LogDebug() << "Int " << pAttrInfo->entries << std::endl; switch ( pAttrInfo->entries ) { case 1: PROCESSCHANNEL_PARTICLE( 1i, i, 0 ); break; case 3: PROCESSCHANNEL_PARTICLE( 3i, vec3i, em::vec3i(0.0f) ); break; } break; case GB_ATTRIB_VECTOR: { LogDebug() << "Vector (Vector3)" << std::endl; if ( empAttrName.compare("position") == 0) { //If this is position, then set the tile layout layout.pointRefine( particleShape.mutableBlocks3f("position") ); particleShape.sync( layout ); } PROCESSCHANNEL_PARTICLE( 3f, vec3f, em::vec3f(0.0f) ); break; } case GB_ATTRIB_MIXED: case GB_ATTRIB_INDEX: default: //Unsupported attribute, so give it a skip. LogDebug() << "Unsupported attribute type for blind copy [" << pAttrInfo->type << "]" << std::endl; continue; break; } if ( pAttrInfo->supported ) LogDebug() << "Supported Blind Copy! Channel: [" << empAttrName << "] Index: " << pAttrInfo->empIndex << std::endl; else { LogDebug() << "Unsupported Blind Copy! Channel: [" << empAttrName << "]" << std::endl; continue; } } //for numAttribs //Loop over the points and transfer attributes for (int i = 0; i < numpoints; i++) { transferParticlePointAttribs( numAttribs, attribList, attrLut, particleShape, ptlist[i] ); } pParticleBody->update(); return EC_SUCCESS; //Ng::TileLayout& layout( pParticleBody->mutableLayout() ); // PLEASE NOTE: this should really be a box close to a particle, instead of (0,0,0)...(1,1,1) but I was in a hurry! // so this will make some "dummy" tiles... layout.worldBoxRefine( em::vec3f(0,0,0), em::vec3f(1,1,1),1,false); particleShape.sync( layout ); //For the sake of simplicity, copy ALL the points in the GDP across. //It will be much slower if we have to filter out all the non-mesh vertices and then remap the vertices to new point numbers. UT_Vector3 pos, v3; GEO_AttributeHandle attr_v, attr_N; //The position attribute needs special/explicit treatment //Get the position buffer from the particleShape em::block3_array3f& vectorBlocks( particleShape.mutableBlocks3f("position") ); em::block3vec3f& vectorData( vectorBlocks(0) ); //Make sure we have enough space in the position attribute vectorData.reserve( _gdp->points().entries() ); for (int i = 0; i < numpoints; i++) { //Set the point position pos = _gdp->points()[i]->getPos(); vectorData.push_back( em::vec3f( pos[0], pos[1], pos[2] ) ); } pParticleBody->update(); LogInfo() << " ************** Done with Particle Shape ************** " << std::endl; return EC_SUCCESS; }
Geo2Emp::ErrorCode Geo2Emp::saveMeshShape(std::list<Nb::Body*>& meshBodyList) { const GEO_Primitive* pprim; const GEO_Point* ppt; GEO_AttributeHandleList attribList; GEO_AttributeHandle* pAttr; GB_Attribute* pBaseAttr; UT_Vector3 pos; Nb::Body* pMeshBody; std::string bodyName, attrname; int ptnum, totalpoints; int numAttribs; //Maps houdini attributes to some cached data std::map<int, AttributeInfo> attrLut; AttributeInfo* pAttrInfo; int attrSize; const GEO_PointAttribDict *pPtAttrDict; if (!_gdp) { //If we don't have a GDP for writing data into Houdini, return error. return EC_NULL_READ_GDP; } LogInfo() << " ************** Saving Mesh Shape ************** " << std::endl; attribList.bindDetail(_gdp); //Add all the GDP point attributes to the attribute list attribList.appendAllAttributes( GEO_POINT_DICT ); numAttribs = attribList.entries(); LogVerbose() << "Number of attributes: " << attribList.entries() << " empty:" << attribList.isEmpty() << std::endl; for (int i = 0; i < numAttribs; i++) { pAttr = attribList[i]; pAttrInfo = &( attrLut[i] ); pAttrInfo->entries = pAttr->entries(); LogDebug() << "pAttr: " << pAttr << " - " << std::endl; LogDebug() << "Attribute #" << i << " - " << pAttr->getName() << " - " << attrSize << std::endl; //Note: if attribute overrides need to be done, this is probably the place. //The attribute creation code *might* need to be moved to another function...or at least some of it //so that it may be shared by other conversion code if ( pAttr->isP() ) { //If we have position, then set up the type manually LogDebug() << "We have a position attribute. Set attributes manually." << std::endl; pAttrInfo->entries = 3; pAttrInfo->type = GB_ATTRIB_VECTOR; } else { //Retrieve attribute info through the standard channels... LogDebug() << "Retrieving attribute data using the Point Dictionary." << std::endl; //Now that we now which attribute we want, find it using the GU_Detail object. //TODO: Is there some beter way of doing this??? pPtAttrDict = dynamic_cast< const GEO_PointAttribDict* >( _gdp->getAttributeDict( GEO_POINT_DICT ) ); pBaseAttr = _gdp->getAttributeDict( GEO_POINT_DICT )->find( pAttr->getName() ); pAttrInfo->type = pBaseAttr->getType(); } LogDebug() << "Switching on attribute type." << std::endl; } //Build a map to separate bodies using their name attributes StringToPrimPolyListMap namesMap; StringToPrimPolyListMap::iterator nameIt; PrimPolyList::iterator polyIt; //Build a vector to remap point numbers. std::vector<int> remappedPtNum; buildTriPrimNamesMap( namesMap ); //Iterate over the names in the map for (nameIt = namesMap.begin(); nameIt != namesMap.end(); nameIt++) { LogInfo() << "Processing Name: " << nameIt->first << std::endl; bodyName = nameIt->first; //List of polygons for this body PrimPolyList &polyList = nameIt->second; //Clear the remapped point numbers for this body remappedPtNum.clear(); //remappedPtNum.resize( _gdp->primitives().entries()*3, -1 ); remappedPtNum.resize( _gdp->points().entries(), -1 ); //Create a Naiad mesh body pMeshBody = Nb::Factory::createBody("Mesh", bodyName); meshBodyList.push_back( pMeshBody ); //get the mutable shapes for the mesh body. Nb::TriangleShape& triShape( pMeshBody->mutableTriangleShape() ); Nb::PointShape& ptShape( pMeshBody->mutablePointShape() ); Nb::Buffer3f& pPosBuf( ptShape.mutableBuffer3f("position") ); pPosBuf.reserve( polyList.size() * 3 ); //Each primitive is treated as a triangle //This preprocessor defition was placed here simply because it is only applicable to this code section //and will fail to work anywhere else. Not to be classified under "best coding practices". #define PROCESSCHANNEL(type, defaults) \ { \ if ( !ptShape.hasChannels ## type (empAttrName) ) \ { \ ptShape.createChannel ## type ( empAttrName, (defaults) ); \ } \ pAttrInfo->empIndex = ptShape.channelIndex( empAttrName ); \ ptShape.mutableBuffer ## type ( empAttrName ).reserve ( polyList.size() * 3 ); \ pAttrInfo->supported = true; \ } //Iterate over the BGEO attributes and create corresponding channels in the EMP //Also, store the channel index for direct lookups when transferring data. for (int i = 0; i < numAttribs; i++) { //Mangle the geo attribute name right now pAttr = attribList[i]; std::string empAttrName; if ( _geoAttribMangle.find( pAttr->getName() ) != _geoAttribMangle.end() ) empAttrName = _geoAttribMangle[ pAttr->getName() ]; else empAttrName = pAttr->getName(); LogDebug() << "Mangling name: " << pAttr->getName() << " ==> " << empAttrName << std::endl; pAttrInfo = &( attrLut[i] ); pAttrInfo->supported = false; pAttrInfo->flipvector = true; //By default, flip vectors if ( std::string(pAttr->getName()).compare("P") == 0 ) pAttrInfo->flipvector = false; pAttrInfo->empIndex = -1; switch ( pAttrInfo->type ) { case GB_ATTRIB_FLOAT: LogDebug() << "Float " << pAttrInfo->entries << std::endl; switch ( pAttrInfo->entries ) { case 1: PROCESSCHANNEL( 1f, 0.0f ); break; case 3: PROCESSCHANNEL( 3f, em::vec3f(0.0f) ); break; } break; case GB_ATTRIB_INT: LogDebug() << "Int " << pAttrInfo->entries << std::endl; break; case GB_ATTRIB_VECTOR: { LogDebug() << "Vector (Vector3)" << std::endl; PROCESSCHANNEL( 3f, em::vec3f(0.0f) ); break; } case GB_ATTRIB_MIXED: case GB_ATTRIB_INDEX: default: //Unsupported attribute, so give it a skip. LogDebug() << "Unsupported attribute type for blind copy [" << pAttrInfo->type << "]" << std::endl; continue; break; } if ( pAttrInfo->supported ) LogDebug() << "Supported Blind Copy! Channel: [" << empAttrName << "] Index: " << pAttrInfo->empIndex << std::endl; else { LogDebug() << "Unsupported Blind Copy! Channel: [" << empAttrName << "]" << std::endl; continue; } } //for numAttribs //Now its time to set the index channel to form faces Nb::Buffer3i& indexBuffer = triShape.mutableBuffer3i("index"); indexBuffer.reserve( polyList.size() ); em::vec3i triVec(0,0,0); //Triangle description for the index buffer totalpoints = 0; LogDebug() << "Starting poly iteration... " << std::endl; //Iterate over all the primitives in this list and remap their point numbers for ( polyIt = polyList.begin(); polyIt != polyList.end(); polyIt++ ) { pprim = *polyIt; if ( pprim->getVertexCount() >= 3 ) { //only extract the first three vertices from the primitive for (int i = 0; i < 3; i++) { //First iterate the points and make sure they have remapped point numbers //NOTE: Houdini & Naiad triangle windings differ. ppt = pprim->getVertex(2-i).getPt(); ptnum = ppt->getNum(); if (remappedPtNum.at( ptnum ) == -1) { //We have an unmapped point for this body //Push the applicable point attributes into each channel transferMeshPointAttribs(numAttribs, attribList, attrLut, ptShape, ppt); //Push the point into the position buffer //pos = ppt->getPos(); //pPosBuf.push_back( em::vec3f( pos[0], pos[1], pos[2]) ); //Record the position at which this point is stored remappedPtNum[ ptnum ] = totalpoints; totalpoints++; } //At this point the current vertex has been remapped at some stage. //Write the remapped index in the triVec triVec[i] = remappedPtNum[ ptnum ]; //Perform a blind copy of all the attributes. } //Push the remapped indices into the body's index buffer. indexBuffer.push_back( triVec ); } else { //Not interested! LogVerbose() << "Warning! Primitive with less than 3 vertices found on body: " << bodyName << " (Vertex count: " << pprim->getVertexCount() << ")" << std::endl; continue; } } } LogInfo() << " ************** Done with Mesh Shape ************** " << std::endl; return EC_SUCCESS; }
void Geo2Emp::transferParticlePointAttribs(int numAttribs, GEO_AttributeHandleList& attribList, std::map<int, AttributeInfo>& attrLut, Nb::ParticleShape& shape, const GEO_Point* ppt) { GEO_AttributeHandle* pAttr; AttributeInfo* pAttrInfo; for (int i = 0; i < numAttribs; i++) { pAttr = attribList[i]; pAttrInfo = &( attrLut[i] ); if (!pAttrInfo->supported) //Skip unsupported attributes continue; pAttr->setElement( ppt ); if (! pAttr->isAttributeValid() ) { LogDebug() << "Invalid attribute handle on supported attribute!! [" << pAttr->getName() << "]" << std::endl; } LogDebug() << "Transferring attribute: " << pAttr->getName() << std::endl; switch ( pAttrInfo->type ) { case GB_ATTRIB_FLOAT: //LogDebug() << "Transfer Float" << pAttrInfo->entries << "[" << pAttr->getName() << "]" << std::endl; switch ( pAttrInfo->entries ) { case 1: { //LogDebug() << "Float1: " << pAttr->getV3() << std::endl; //Get the channel from the point shape em::block3_array1f& vecData = shape.mutableBlocks1f( pAttrInfo->empIndex ); //Write the data into the buffer vecData(0).push_back( pAttr->getF() ); } break; case 3: { LogDebug() << "Float3: " << pAttr->getV3() << std::endl; //Get the channel from the particle shape em::block3_array3f& vecData = shape.mutableBlocks3f( pAttrInfo->empIndex ); //Write the data into the buffer vecData(0).push_back( em::vec3f( pAttr->getF(0), pAttr->getF(1), pAttr->getF(2) ) ); } break; } break; case GB_ATTRIB_INT: LogDebug() << "Int " << pAttrInfo->entries << std::endl; switch ( pAttrInfo->entries ) { case 1: { //LogDebug() << "Float1: " << pAttr->getV3() << std::endl; //Get the channel from the point shape em::block3_array1i& vecData = shape.mutableBlocks1i( pAttrInfo->empIndex ); //Write the data into the buffer vecData(0).push_back( pAttr->getI() ); } break; case 3: { LogDebug() << "Int3: " << std::endl; //Get the channel from the particle shape em::block3_array3i& vecData = shape.mutableBlocks3i( pAttrInfo->empIndex ); //Write the data into the buffer vecData(0).push_back( em::vec3i( pAttr->getI(0), pAttr->getI(1), pAttr->getI(2) ) ); } break; } break; case GB_ATTRIB_VECTOR: { //LogDebug() << "Transfer Vector3 [" << pAttr->getName() << "] " << pAttr->getF(0) << "," << pAttr->getF(1) << "," << pAttr->getF(2)<< std::endl; //If we have a vector, we need to invert it (reverse winding). em::block3_array3f& vecData = shape.mutableBlocks3f( pAttrInfo->empIndex ); //Write the data into the buffer vecData(0).push_back( em::vec3f( pAttr->getF(0), pAttr->getF(1), pAttr->getF(2) ) ); break; } case GB_ATTRIB_MIXED: case GB_ATTRIB_INDEX: default: //Unsupported attribute, so give it a skip. LogDebug() << " !!!!! SHOULDNT GET THIS !!!! Unsupported attribute type for blind copy [" << pAttrInfo->type << "]" << std::endl; continue; break; } } }
OP_ERROR SOP_IntersectRay::cookMySop(OP_Context &context) { double t; float edgelength, primarea, generatepoints; int verbose; // We optionally add points in self-penetration places: GB_PointGroup *hitPointsGroup; UT_RefArray<UT_Vector3> hitPoints; if (lockInputs(context) >= UT_ERROR_ABORT) return error(); t = context.getTime(); duplicatePointSource(0, context); edgelength = EDGELENGTH(t); primarea = PRIMAREA(t); verbose = VERBOSE(t); generatepoints = GENERATEPOINTS(t); // Normals: GEO_AttributeHandle nH; GEO_AttributeHandle cdH; nH = gdp->getAttribute(GEO_POINT_DICT, "N"); cdH = gdp->getAttribute(GEO_POINT_DICT, "Cd"); // RayInfo parms: //float max = 1E18f; // Max specified by edge length... float min = 0.0f; float tol = 1e-1F; // Rayhit objects: GU_RayFindType itype = GU_FIND_ALL; GU_RayIntersect intersect = GU_RayIntersect(gdp); // Profile: //Timer timer = Timer(); //float rayhit_time = 0; //float vertex_time = 0; // Here we determine which groups we have to work on. if (error() < UT_ERROR_ABORT && cookInputGroups(context) < UT_ERROR_ABORT) { UT_AutoInterrupt progress("Checking for self-intersections..."); const GEO_Primitive *ppr; FOR_ALL_GROUP_PRIMITIVES(gdp, myGroup, ppr) { // Check if user requested abort if (progress.wasInterrupted()) break; // Get rid of primitives smaller than primarea: if ( ppr->calcArea() < primarea ) continue; for (int j = 0; j < ppr->getVertexCount() - 1; j++) { // Get data; // TODO: This is extremally inefficent. // TODO: Why do we crash with uv vetrex attributes!? const GEO_Vertex ppv1 = ppr->getVertex(j); const GEO_Vertex ppv2 = ppr->getVertex(j+1); const GEO_Point *ppt1 = ppv1.getPt(); const GEO_Point *ppt2 = ppv2.getPt(); // Vertices positions: UT_Vector3 p1 = ppt1->getPos(); UT_Vector3 p2 = ppt2->getPos(); // Ray direction: p2 = p2 - p1; // Get rid of edges shorter than edgelength: if (p2.length() < edgelength) continue; // hit info with max distance equal edge length: GU_RayInfo hitinfo = GU_RayInfo(p2.length(), min, itype, tol); p2.normalize(); // Send ray: if (intersect.sendRay(p1, p2, hitinfo)) { UT_RefArray<GU_RayInfoHit> hits = *(hitinfo.myHitList); for(int j = 0; j < hits.entries(); j++) { const GEO_Primitive *prim = hits[j].prim; const GEO_PrimPoly *poly = (const GEO_PrimPoly *) prim; //TODO: Prims only? // We are interested only ff points are not part of prims...: if (poly->find(*ppt1) == -1 && poly->find(*ppt2)== -1) { if (verbose) printf("Edge: %i-%i intersects with prim:%d \n",ppt1->getNum(), ppt2->getNum(), prim->getNum()); // Save hit position as points: if (generatepoints) { UT_Vector4 pos; float u = hits[j].u; float v = hits[j].v; if (!prim->evaluateInteriorPoint(pos, u, v)) hitPoints.append(pos); } // TODO: Should I indicate penetration with red color on both ends of edge?: cdH.setElement(ppt1); cdH.setV3(UT_Vector3(1.0, 0.0, 0.0)); cdH.setElement(ppt2); cdH.setV3(UT_Vector3(1.0, 0.0, 0.0)); } } } } } if (generatepoints) { hitPointsGroup = gdp->newPointGroup("__self_penetrate", false); for (int i = 0; i < hitPoints.entries(); i++) { GEO_Point *point; point = gdp->appendPoint(); hitPointsGroup->add(point); point->setPos(hitPoints(i)); } } }
OP_ERROR SOP_FluidSolver2D::cookMySop(OP_Context &context) { oldf = f; double t = context.getTime(); int f = context.getFrame(); UT_Interrupt *boss; GU_PrimVolume *volume; OP_Node::flags().timeDep = 1; fluidSolver->fps = OPgetDirector()->getChannelManager()->getSamplesPerSec(); int newResX = RESX(t); int newResY = RESY(t); if ( newResX != fluidSolver->res.x || newResY != fluidSolver->res.y) { fluidSolver->changeFluidRes(newResX,newResY); } UT_Vector3 fluidPos(POSX(t), POSY(t), POSZ(t)); UT_Vector3 fluidRot(ROTX(t), ROTY(t), ROTZ(t)); fluidRot.degToRad(); fluidSolver->fluidSize.x = FLUIDSIZEX(t); fluidSolver->fluidSize.y = FLUIDSIZEY(t); fluidSolver->borderNegX = BORDERNEGX(t); fluidSolver->borderPosX = BORDERPOSX(t); fluidSolver->borderNegY = BORDERNEGY(t); fluidSolver->borderPosY = BORDERPOSY(t); fluidSolver->preview = PREVIEW(t); fluidSolver->previewType = PREVIEWTYPE(t); fluidSolver->bounds = BOUNDS(t); fluidSolver->substeps = SUBSTEPS(t); fluidSolver->jacIter = JACITER(t); fluidSolver->densDis = DENSDIS(t); fluidSolver->densBuoyStrength = DENSBUOYSTRENGTH(t); float ddirX = DENSBUOYDIRX(t); float ddirY = DENSBUOYDIRY(t); fluidSolver->densBuoyDir = cu::make_float2(ddirX,ddirY); fluidSolver->velDamp = VELDAMP(t); fluidSolver->vortConf = VORTCONF(t); fluidSolver->noiseStr = NOISESTR(t); fluidSolver->noiseFreq = NOISEFREQ(t); fluidSolver->noiseOct = NOISEOCT(t); fluidSolver->noiseLacun = NOISELACUN(t); fluidSolver->noiseSpeed = NOISESPEED(t); fluidSolver->noiseAmp = NOISEAMP(t); if (error() < UT_ERROR_ABORT) { boss = UTgetInterrupt(); gdp->clearAndDestroy(); // Start the interrupt server if (boss->opStart("Building Volume")){ static float zero = 0.0; #ifdef HOUDINI_11 GB_AttributeRef fluidAtt = gdp->addAttrib("cudaFluidPreview", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(fluidAtt, fluidSolver->preview); GB_AttributeRef solverIdAtt = gdp->addAttrib("solverId", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(solverIdAtt, fluidSolver->id); #else GA_WOAttributeRef fluidAtt = gdp->addIntTuple(GA_ATTRIB_DETAIL, "cudaFluidPreview", 1); gdp->element().setValue<int>(fluidAtt, fluidSolver->preview); GA_WOAttributeRef solverIdAtt = gdp->addIntTuple(GA_ATTRIB_DETAIL, "solverId", 1); gdp->element().setValue<int>(solverIdAtt, fluidSolver->id); #endif UT_Matrix3 xform; const UT_XformOrder volXFormOrder; volume = (GU_PrimVolume *)GU_PrimVolume::build(gdp); #ifdef HOUDINI_11 volume->getVertex().getPt()->getPos() = fluidPos; #else volume->getVertexElement(0).getPt()->setPos(fluidPos); #endif xform.identity(); xform.scale(fluidSolver->fluidSize.x*0.5, fluidSolver->fluidSize.y*0.5, 0.25); xform.rotate(fluidRot.x(), fluidRot.y(), fluidRot.z(), volXFormOrder); volume->setTransform(xform); xform.identity(); xform.rotate(fluidRot.x(), fluidRot.y(), fluidRot.z(), volXFormOrder); xform.invert(); if(lockInputs(context) >= UT_ERROR_ABORT) return error(); if(getInput(0)){ GU_Detail* emittersInput = (GU_Detail*)inputGeo(0, context); GEO_PointList emittersList = emittersInput->points(); int numEmitters = emittersList.entries(); if (numEmitters != fluidSolver->nEmit) { delete fluidSolver->emitters; fluidSolver->nEmit = numEmitters; fluidSolver->emitters = new FluidEmitter[numEmitters]; } GEO_AttributeHandle radAh, amountAh; radAh = emittersInput->getPointAttribute("radius"); amountAh = emittersInput->getPointAttribute("amount"); for (int i = 0; i < numEmitters; i++) { UT_Vector4 emitPos = emittersList[i]->getPos(); UT_Vector3 emitPos3(emitPos); emitPos3 -= fluidPos; emitPos3 = emitPos3*xform; fluidSolver->emitters[i].posX = emitPos3.x(); fluidSolver->emitters[i].posY = emitPos3.y(); radAh.setElement(emittersList[i]); amountAh.setElement(emittersList[i]); fluidSolver->emitters[i].radius = radAh.getF(0); fluidSolver->emitters[i].amount = amountAh.getF(0); } } else { fluidSolver->nEmit = 0; } if(getInput(1)) { GU_Detail* collidersInput = (GU_Detail*)inputGeo(1, context); GEO_PointList collidersList = collidersInput->points(); int numColliders = collidersList.entries(); if (numColliders != fluidSolver->nColliders) { delete fluidSolver->colliders; fluidSolver->nColliders = numColliders; fluidSolver->colliders = new Collider[numColliders]; } GEO_AttributeHandle colRadAh; colRadAh = collidersInput->getPointAttribute("radius"); for (int i = 0; i < numColliders; i++) { UT_Vector4 colPos = collidersList[i]->getPos(); UT_Vector3 colPos3(colPos); colPos3 -= fluidPos; colPos3 = colPos3*xform; if (f > STARTFRAME(t)) { fluidSolver->colliders[i].oldPosX = fluidSolver->colliders[i].posX; fluidSolver->colliders[i].oldPosY = fluidSolver->colliders[i].posY; } else { fluidSolver->colliders[i].oldPosX = colPos3.x(); fluidSolver->colliders[i].oldPosY = colPos3.y(); } fluidSolver->colliders[i].posX = colPos3.x(); fluidSolver->colliders[i].posY = colPos3.y(); colRadAh.setElement(collidersList[i]); fluidSolver->colliders[i].radius = colRadAh.getF(0); } } else { fluidSolver->nColliders = 0; } unlockInputs(); if (f <= STARTFRAME(t)) { fluidSolver->resetFluid(); if (fluidSolver->preview != 1) { { UT_VoxelArrayWriteHandleF handle = volume->getVoxelWriteHandle(); handle->constant(0); } } } else { if (f!=oldf) { fluidSolver->solveFluid(); } if (fluidSolver->preview != 1) { cu::cudaMemcpy( fluidSolver->host_dens, fluidSolver->dev_dens, fluidSolver->res.x*fluidSolver->res.y*sizeof(float), cu::cudaMemcpyDeviceToHost ); { UT_VoxelArrayWriteHandleF handle = volume->getVoxelWriteHandle(); handle->size(fluidSolver->res.x, fluidSolver->res.y, 1); for (int i = 0; i < fluidSolver->res.x; i++) { for (int j = 0; j < fluidSolver->res.y; j++) { handle->setValue(i, j, 0, fluidSolver->host_dens[(j*fluidSolver->res.x + i)]); } } } } } select(GU_SPrimitive); } // Tell the interrupt server that we've completed. Must do this // regardless of what opStart() returns. boss->opEnd(); } gdp->notifyCache(GU_CACHE_ALL); return error(); }
OP_ERROR SOP_FluidSolver3D::cookMySop(OP_Context &context) { oldf = f; f = context.getFrame(); double t = context.getTime(); fluidSolver->fps = OPgetDirector()->getChannelManager()->getSamplesPerSec(); UT_Interrupt *boss; GU_PrimVolume *volume; GU_PrimVolume *velXVolume; GU_PrimVolume *velYVolume; GU_PrimVolume *velZVolume; OP_Node::flags().timeDep = 1; int newResX = RESX(t); int newResY = RESY(t); int newResZ = RESZ(t); if ( newResX != fluidSolver->res.width || newResY != fluidSolver->res.height || newResZ != fluidSolver->res.depth) { fluidSolver->changeFluidRes(newResX,newResY,newResZ); } UT_Vector3 fluidPos(POSX(t), POSY(t), POSZ(t)); UT_Vector3 fluidRot(ROTX(t), ROTY(t), ROTZ(t)); fluidRot.degToRad(); fluidSolver->fluidSize.x = FLUIDSIZEX(t); fluidSolver->fluidSize.y = FLUIDSIZEY(t); fluidSolver->fluidSize.z = FLUIDSIZEZ(t); fluidSolver->borderNegX = BORDERNEGX(t); fluidSolver->borderPosX = BORDERPOSX(t); fluidSolver->borderNegY = BORDERNEGY(t); fluidSolver->borderPosY = BORDERPOSY(t); fluidSolver->borderNegZ = BORDERNEGZ(t); fluidSolver->borderPosZ = BORDERPOSZ(t); fluidSolver->substeps = SUBSTEPS(t); fluidSolver->jacIter = JACITER(t); fluidSolver->densDis = DENSDIS(t); fluidSolver->densBuoyStrength = DENSBUOYSTRENGTH(t); float ddirX = DENSBUOYDIRX(t); float ddirY = DENSBUOYDIRY(t); float ddirZ = DENSBUOYDIRZ(t); fluidSolver->densBuoyDir = cu::make_float3(ddirX,ddirY,ddirZ); fluidSolver->velDamp = VELDAMP(t); fluidSolver->vortConf = VORTCONF(t); fluidSolver->noiseStr = NOISESTR(t); fluidSolver->noiseFreq = NOISEFREQ(t); fluidSolver->noiseOct = NOISEOCT(t); fluidSolver->noiseLacun = NOISELACUN(t); fluidSolver->noiseSpeed = NOISESPEED(t); fluidSolver->noiseAmp = NOISEAMP(t); fluidSolver->preview = PREVIEW(t); fluidSolver->drawCube = DRAWCUBE(t); fluidSolver->opaScale = OPASCALE(t); fluidSolver->stepMul = STEPMUL(t); fluidSolver->displayRes = DISPLAYRES(t); fluidSolver->doShadows = DOSHADOWS(t); float lightPosX = LIGHTPOSX(t); float lightPosY = LIGHTPOSY(t); float lightPosZ = LIGHTPOSZ(t); fluidSolver->lightPos = cu::make_float3(lightPosX,lightPosY,lightPosZ); fluidSolver->shadowDens = SHADOWDENS(t); fluidSolver->shadowStepMul = SHADOWSTEPMUL(t); fluidSolver->shadowThres = SHADOWTHRES(t); fluidSolver->displaySlice = DISPLAYSLICE(t); fluidSolver->sliceType = SLICETYPE(t); fluidSolver->sliceAxis = SLICEAXIS(t); fluidSolver->slicePos = SLICEPOS(t); fluidSolver->sliceBounds = SLICEBOUNDS(t); if (error() < UT_ERROR_ABORT) { boss = UTgetInterrupt(); gdp->clearAndDestroy(); // Start the interrupt server if (boss->opStart("Building Volume")){ static float zero = 0.0; GB_AttributeRef fluidAtt = gdp->addAttrib("cudaFluid3DPreview", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(fluidAtt, fluidSolver->preview); GB_AttributeRef fluidSliceAtt = gdp->addAttrib("sliceDisplay", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(fluidSliceAtt, fluidSolver->displaySlice); GB_AttributeRef solverIdAtt = gdp->addAttrib("solverId", sizeof(int), GB_ATTRIB_INT, &zero); gdp->attribs().getElement().setValue<int>(solverIdAtt, fluidSolver->id); GEO_AttributeHandle name_gah; int def = -1; gdp->addPrimAttrib("name", sizeof(int), GB_ATTRIB_INDEX, &def); name_gah = gdp->getPrimAttribute("name"); UT_Matrix3 xform; const UT_XformOrder volXFormOrder; volume = (GU_PrimVolume *)GU_PrimVolume::build(gdp); volume->getVertex().getPt()->getPos() = fluidPos; xform.identity(); xform.scale(fluidSolver->fluidSize.x*0.5, fluidSolver->fluidSize.y*0.5, fluidSolver->fluidSize.z*0.5); xform.rotate(fluidRot.x(), fluidRot.y(), fluidRot.z(), volXFormOrder); volume->setTransform(xform); name_gah.setElement(volume); name_gah.setString("density"); velXVolume = (GU_PrimVolume *)GU_PrimVolume::build(gdp); velXVolume->getVertex().getPt()->getPos() = fluidPos; velXVolume->setTransform(xform); name_gah.setElement(velXVolume); name_gah.setString("vel.x"); velYVolume = (GU_PrimVolume *)GU_PrimVolume::build(gdp); velYVolume->getVertex().getPt()->getPos() = fluidPos; velYVolume->setTransform(xform); name_gah.setElement(velYVolume); name_gah.setString("vel.y"); velZVolume = (GU_PrimVolume *)GU_PrimVolume::build(gdp); velZVolume->getVertex().getPt()->getPos() = fluidPos; velZVolume->setTransform(xform); name_gah.setElement(velZVolume); name_gah.setString("vel.z"); xform.identity(); xform.rotate(fluidRot.x(), fluidRot.y(), fluidRot.z(), volXFormOrder); xform.invert(); if(lockInputs(context) >= UT_ERROR_ABORT) return error(); if(getInput(0)){ GU_Detail* emittersInput = (GU_Detail*)inputGeo(0, context); GEO_PointList emittersList = emittersInput->points(); int numEmitters = emittersList.entries(); if (numEmitters != fluidSolver->nEmit) { delete fluidSolver->emitters; fluidSolver->nEmit = numEmitters; fluidSolver->emitters = new VHFluidEmitter[numEmitters]; } GEO_AttributeHandle radAh, amountAh; radAh = emittersInput->getPointAttribute("radius"); amountAh = emittersInput->getPointAttribute("amount"); for (int i = 0; i < numEmitters; i++) { UT_Vector4 emitPos = emittersList[i]->getPos(); UT_Vector3 emitPos3(emitPos); emitPos3 -= fluidPos; emitPos3 = emitPos3*xform; fluidSolver->emitters[i].posX = emitPos3.x(); fluidSolver->emitters[i].posY = emitPos3.y(); fluidSolver->emitters[i].posZ = emitPos3.z(); radAh.setElement(emittersList[i]); amountAh.setElement(emittersList[i]); fluidSolver->emitters[i].radius = radAh.getF(0); fluidSolver->emitters[i].amount = amountAh.getF(0); } } else { fluidSolver->nEmit = 0; } if(getInput(1)) { GU_Detail* collidersInput = (GU_Detail*)inputGeo(1, context); GEO_PointList collidersList = collidersInput->points(); int numColliders = collidersList.entries(); if (numColliders != fluidSolver->nColliders) { delete fluidSolver->colliders; fluidSolver->nColliders = numColliders; fluidSolver->colliders = new VHFluidCollider[numColliders]; } GEO_AttributeHandle colRadAh; colRadAh = collidersInput->getPointAttribute("radius"); for (int i = 0; i < numColliders; i++) { UT_Vector4 colPos = collidersList[i]->getPos(); UT_Vector3 colPos3(colPos); colPos3 -= fluidPos; colPos3 = colPos3*xform; if (f > STARTFRAME(t)) { fluidSolver->colliders[i].oldPosX = fluidSolver->colliders[i].posX; fluidSolver->colliders[i].oldPosY = fluidSolver->colliders[i].posY; fluidSolver->colliders[i].oldPosZ = fluidSolver->colliders[i].posZ; } else { fluidSolver->colliders[i].oldPosX = colPos3.x(); fluidSolver->colliders[i].oldPosY = colPos3.y(); fluidSolver->colliders[i].oldPosZ = colPos3.z(); } fluidSolver->colliders[i].posX = colPos3.x(); fluidSolver->colliders[i].posY = colPos3.y(); fluidSolver->colliders[i].posZ = colPos3.z(); colRadAh.setElement(collidersList[i]); fluidSolver->colliders[i].radius = colRadAh.getF(0); } } else { fluidSolver->nColliders = 0; } unlockInputs(); if (f <= STARTFRAME(t)) { fluidSolver->resetFluid(); if (COPYDENS(t)) { { UT_VoxelArrayWriteHandleF handle = volume->getVoxelWriteHandle(); handle->constant(0); UT_VoxelArrayWriteHandleF velXHandle = velXVolume->getVoxelWriteHandle(); velXHandle->constant(0); UT_VoxelArrayWriteHandleF velYHandle = velYVolume->getVoxelWriteHandle(); velYHandle->constant(0); UT_VoxelArrayWriteHandleF velZHandle = velZVolume->getVoxelWriteHandle(); velZHandle->constant(0); } } } else { if (f!=oldf) { fluidSolver->solveFluid(); } if (COPYDENS(t)) { cu::cudaMemcpy( fluidSolver->host_dens, fluidSolver->dev_dens, fluidSolver->res.width*fluidSolver->res.height*fluidSolver->res.depth*sizeof(float), cu::cudaMemcpyDeviceToHost ); { UT_VoxelArrayWriteHandleF handle = volume->getVoxelWriteHandle(); handle->size(fluidSolver->res.width, fluidSolver->res.height, fluidSolver->res.depth); for (int i = 0; i < fluidSolver->res.width; i++) { for (int j = 0; j < fluidSolver->res.height; j++) { for (int k = 0; k < fluidSolver->res.depth; k++) { handle->setValue(i, j, k, fluidSolver->host_dens[k*fluidSolver->res.width*fluidSolver->res.height + j*fluidSolver->res.width + i]); } } } } if (COPYVEL(t)) { cu::cudaMemcpy( fluidSolver->host_vel, fluidSolver->dev_vel, fluidSolver->res.width*fluidSolver->res.height*fluidSolver->res.depth*sizeof(cu::float4), cu::cudaMemcpyDeviceToHost ); { UT_VoxelArrayWriteHandleF velXHandle = velXVolume->getVoxelWriteHandle(); velXHandle->size(fluidSolver->res.width, fluidSolver->res.height, fluidSolver->res.depth); UT_VoxelArrayWriteHandleF velYHandle = velYVolume->getVoxelWriteHandle(); velYHandle->size(fluidSolver->res.width, fluidSolver->res.height, fluidSolver->res.depth); UT_VoxelArrayWriteHandleF velZHandle = velZVolume->getVoxelWriteHandle(); velZHandle->size(fluidSolver->res.width, fluidSolver->res.height, fluidSolver->res.depth); for (int i = 0; i < fluidSolver->res.width; i++) { for (int j = 0; j < fluidSolver->res.height; j++) { for (int k = 0; k < fluidSolver->res.depth; k++) { velXHandle->setValue(i, j, k, fluidSolver->host_vel[4*(k*fluidSolver->res.width*fluidSolver->res.height + j*fluidSolver->res.width + i)]); velYHandle->setValue(i, j, k, fluidSolver->host_vel[4*(k*fluidSolver->res.width*fluidSolver->res.height + j*fluidSolver->res.width + i)+1]); velZHandle->setValue(i, j, k, fluidSolver->host_vel[4*(k*fluidSolver->res.width*fluidSolver->res.height + j*fluidSolver->res.width + i)+2]); } } } } } } } select(GU_SPrimitive); } // Tell the interrupt server that we've completed. Must do this // regardless of what opStart() returns. boss->opEnd(); } gdp->notifyCache(GU_CACHE_ALL); return error(); }