GA_Detail::IOStatus GEO_CobIOTranslator::fileSaveToFile( const GEO_Detail *geo, ostream &os, const char *fileName ) { ((ofstream&)os).close(); GU_DetailHandle handle; handle.allocateAndSet( (GU_Detail*)geo, false ); FromHoudiniGeometryConverterPtr converter = FromHoudiniGeometryConverter::create( handle ); if ( !converter ) { return false; } ObjectPtr object = converter->convert(); if ( !object ) { return false; } try { WriterPtr writer = Writer::create( object, fileName ); writer->write(); } catch ( IECore::Exception e ) { return false; } return true; }
ObjectPtr FromHoudiniGroupConverter::doDetailConversion( const GU_Detail *geo, const CompoundObject *operands ) const { GU_DetailHandle handle; handle.allocateAndSet( (GU_Detail*)geo, false ); FromHoudiniGeometryConverterPtr converter = FromHoudiniGeometryConverter::create( handle ); if ( !converter || converter->isInstanceOf( FromHoudiniGroupConverter::staticTypeId() ) ) { /// \todo: if we're in PrimitiveGroup mode, but names exist, we return 0 when we should be returning a Group return 0; } // transfer the common parameter values CompoundParameter *parameters = converter->parameters(); const CompoundParameter::ParameterMap ¶meterMap = parameters->parameters(); const CompoundObject::ObjectMap &values = operands->members(); for ( CompoundObject::ObjectMap::const_iterator it = values.begin(); it != values.end(); ++it ) { CompoundParameter::ParameterMap::const_iterator pIt = parameterMap.find( it->first ); if ( pIt != parameterMap.end() && pIt->second->defaultValue()->typeId() == it->second->typeId() ) { parameters->setParameterValue( it->first, it->second ); } } return converter->convert(); }
GEO_Primitive *GU_CortexPrimitive::doConvert( GU_ConvertParms &parms ) { if ( !m_object ) { return 0; } #if UT_MAJOR_VERSION_INT >= 13 GA_PrimCompat::TypeMask type = parms.toType(); #else GA_PrimCompat::TypeMask type = parms.toType; #endif /// \todo: should the GEO_PrimTypeCompat be registered with the converters? if ( m_object->isInstanceOf( IECore::MeshPrimitiveTypeId ) && type == GEO_PrimTypeCompat::GEOPRIMPOLY ) { GU_DetailHandle handle; handle.allocateAndSet( (GU_Detail*)getParent(), false ); ToHoudiniPolygonsConverterPtr converter = new ToHoudiniPolygonsConverter( IECore::runTimeCast<const IECore::MeshPrimitive>( m_object.get() ) ); if ( !converter->convert( handle ) ) { return 0; } } /// \todo: support for CurvesPrimitive, PointsPrimitive, and any other existing converters return 0; }
ConstObjectPtr HoudiniScene::readObject( double time ) const { OBJ_Node *objNode = retrieveNode( true )->castToOBJNode(); if ( !objNode ) { return 0; } if ( objNode->getObjectType() == OBJ_GEOMETRY ) { OP_Context context( time ); GU_DetailHandle handle = objNode->getRenderGeometryHandle( context, false ); if ( !m_splitter || ( handle != m_splitter->handle() ) ) { m_splitter = new DetailSplitter( handle ); } GU_DetailHandle newHandle = m_splitter->split( contentPathValue() ); FromHoudiniGeometryConverterPtr converter = FromHoudiniGeometryConverter::create( ( newHandle.isNull() ) ? handle : newHandle ); if ( !converter ) { return 0; } return converter->convert(); } /// \todo: need to account for cameras and lights return 0; }
GU_DetailHandle LiveScene::contentHandle() const { std::string name; SceneInterface::Path path; relativeContentPath( path ); pathToString( path, name ); GU_DetailHandle handle = m_splitter->split( name.c_str() ); // we need to try again, in case the user didn't use a / prefix on the shape name if ( handle.isNull() && m_contentIndex == 1 && !path.empty() && path[0] != "" ) { handle = m_splitter->split( &name.c_str()[1] ); } return handle; }
void SOP_CortexConverter::doConvert( const GU_DetailHandle &handle, const std::string &name, ResultType type, const std::string &attributeFilter, bool convertStandardAttributes ) { if ( handle.isNull() ) { addError( SOP_MESSAGE, ( "Could not extract the geometry named " + name ).c_str() ); return; } FromHoudiniGeometryConverterPtr fromConverter = FromHoudiniGeometryConverter::create( handle ); if ( !fromConverter ) { addError( SOP_MESSAGE, ( "Could not convert the geometry named " + name ).c_str() ); return; } IECore::ObjectPtr result = fromConverter->convert(); if ( !result ) { addError( SOP_MESSAGE, ( "Could not find Cortex Object named " + name + " on input geometry" ).c_str() ); return; } if ( IECore::ParameterisedProcedural *procedural = IECore::runTimeCast<IECore::ParameterisedProcedural>( result.get() ) ) { IECore::CapturingRendererPtr renderer = new IECore::CapturingRenderer(); // We are acquiring and releasing the GIL here to ensure that it is released when we render. This has // to be done because a procedural might jump between c++ and python a few times (i.e. if it spawns // subprocedurals that are implemented in python). In a normal call to cookMySop, this wouldn't be an // issue, but if cookMySop was called from HOM, hou.Node.cook appears to be holding onto the GIL. IECorePython::ScopedGILLock gilLock; { IECorePython::ScopedGILRelease gilRelease; { IECore::WorldBlock worldBlock( renderer ); procedural->render( renderer.get() ); } } result = boost::const_pointer_cast<IECore::Object>( IECore::runTimeCast<const IECore::Object>( renderer->world() ) ); } ToHoudiniGeometryConverterPtr converter = ( type == Cortex ) ? new ToHoudiniCortexObjectConverter( result.get() ) : ToHoudiniGeometryConverter::create( result.get() ); converter->nameParameter()->setTypedValue( name ); converter->attributeFilterParameter()->setTypedValue( attributeFilter ); converter->convertStandardAttributesParameter()->setTypedValue( convertStandardAttributes ); if ( !converter->convert( myGdpHandle ) ) { addError( SOP_MESSAGE, ( "Could not convert the Cortex Object named " + name + " to Houdini geometry" ).c_str() ); } }
GA_Detail::IOStatus GEO_CobIOTranslator::fileLoad( GEO_Detail *geo, UT_IStream &is, int ate_magic ) { ((UT_IFStream&)is).close(); ConstVisibleRenderablePtr renderable = 0; try { ReaderPtr reader = Reader::create( is.getLabel() ); if ( reader->isInstanceOf( ParticleReaderTypeId ) ) { reader->parameters()->parameter<IntParameter>( "realType" )->setNumericValue( ParticleReader::Float ); } renderable = runTimeCast<VisibleRenderable>( reader->read() ); } catch ( IECore::Exception e ) { return false; } if ( !renderable ) { return false; } ToHoudiniGeometryConverterPtr converter = ToHoudiniGeometryConverter::create( renderable ); if ( !converter ) { return false; } GU_DetailHandle handle; handle.allocateAndSet( (GU_Detail*)geo, false ); return converter->convert( handle ); }
GA_Detail::IOStatus GEO_CobIOTranslator::fileLoad( GEO_Detail *geo, UT_IStream &is, int ate_magic ) { ((UT_IFStream&)is).close(); ConstObjectPtr object = 0; try { ReaderPtr reader = Reader::create( is.getLabel() ); if ( !reader ) { return false; } object = reader->read(); } catch ( IECore::Exception e ) { return false; } if ( !object ) { return false; } ToHoudiniGeometryConverterPtr converter = ToHoudiniGeometryConverter::create( object.get() ); if ( !converter ) { return false; } GU_DetailHandle handle; handle.allocateAndSet( (GU_Detail*)geo, false ); return converter->convert( handle ); }
void SOP_CortexConverter::doPassThrough( const GU_DetailHandle &handle, const std::string &name ) { if ( handle.isNull() ) { addError( SOP_MESSAGE, ( "Could not pass through the geometry named " + name ).c_str() ); return; } GU_DetailHandleAutoReadLock readHandle( handle ); const GU_Detail *inputGeo = readHandle.getGdp(); if ( !inputGeo ) { addError( SOP_MESSAGE, ( "Could not pass through the geometry named " + name ).c_str() ); return; } gdp->merge( *inputGeo ); }
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(); } }
bool ToHoudiniGroupConverter::doConversion( const VisibleRenderable *renderable, GU_Detail *geo ) const { const Group *group = IECore::runTimeCast<const Group>( renderable ); if ( !group ) { return false; } Imath::M44f transform = ( runTimeCast<const M44fData>( m_transformParameter->getValue() ) )->readable(); const Transform *groupTransform = group->getTransform(); if ( groupTransform ) { transform = transform * groupTransform->transform(); } TransformOpPtr transformOp = new TransformOp(); M44fDataPtr transformData = new M44fData( transform ); transformOp->matrixParameter()->setValue( transformData ); std::string groupName = nameParameter()->getTypedValue(); if ( groupName == "" ) { // backwards compatibility with older data if ( const StringData *groupNameData = group->blindData()->member<StringData>( "name" ) ) { groupName = groupNameData->readable(); } } const std::string &attribFilter = attributeFilterParameter()->getTypedValue(); bool convertStandardAttributes = convertStandardAttributesParameter()->getTypedValue(); size_t i = 0; const Group::ChildContainer &children = group->children(); for ( Group::ChildContainer::const_iterator it=children.begin(); it != children.end(); ++it, ++i ) { ConstVisibleRenderablePtr child = *it; ConstPrimitivePtr primitive = runTimeCast<const Primitive>( child ); if ( primitive ) { transformOp->inputParameter()->setValue( constPointerCast<Primitive>( primitive ) ); child = staticPointerCast<VisibleRenderable>( transformOp->operate() ); } ToHoudiniGeometryConverterPtr converter = ToHoudiniGeometryConverter::create( child ); if ( !converter ) { continue; } std::string name = groupName; if ( const StringData *childNameData = child->blindData()->member<StringData>( "name" ) ) { const std::string &childName = childNameData->readable(); if ( childName != "" ) { if ( groupName != "" ) { name += "/"; } name += childName; } } converter->nameParameter()->setTypedValue( name ); converter->attributeFilterParameter()->setTypedValue( attribFilter ); converter->convertStandardAttributesParameter()->setTypedValue( convertStandardAttributes ); ToHoudiniGroupConverter *groupConverter = runTimeCast<ToHoudiniGroupConverter>( converter ); if ( groupConverter ) { groupConverter->transformParameter()->setValue( transformData ); } GU_DetailHandle handle; handle.allocateAndSet( geo, false ); if ( !converter->convert( handle ) ) { continue; } } return true; }
void HoudiniScene::readTags( NameList &tags, bool includeChildren ) const { tags.clear(); const OP_Node *node = retrieveNode(); if ( !node ) { return; } // add user supplied tags if we're not inside a SOP if ( !m_contentIndex && node->hasParm( pTags.getToken() ) ) { UT_String parmTagStr; node->evalString( parmTagStr, pTags.getToken(), 0, 0 ); if ( !parmTagStr.equal( UT_String::getEmptyString() ) ) { UT_WorkArgs tokens; parmTagStr.tokenize( tokens, " " ); for ( int i = 0; i < tokens.getArgc(); ++i ) { tags.push_back( tokens[i] ); } } } // add tags from the registered tag readers std::vector<CustomTagReader> &tagReaders = customTagReaders(); for ( std::vector<CustomTagReader>::const_iterator it = tagReaders.begin(); it != tagReaders.end(); ++it ) { NameList values; it->m_read( node, values, includeChildren ); tags.insert( tags.end(), values.begin(), values.end() ); } // add tags based on primitive groups OBJ_Node *contentNode = retrieveNode( true )->castToOBJNode(); if ( contentNode && contentNode->getObjectType() == OBJ_GEOMETRY && m_splitter ) { GU_DetailHandle newHandle = m_splitter->split( contentPathValue() ); if ( !newHandle.isNull() ) { GU_DetailHandleAutoReadLock readHandle( newHandle ); if ( const GU_Detail *geo = readHandle.getGdp() ) { GA_Range prims = geo->getPrimitiveRange(); for ( GA_GroupTable::iterator<GA_ElementGroup> it=geo->primitiveGroups().beginTraverse(); !it.atEnd(); ++it ) { GA_PrimitiveGroup *group = static_cast<GA_PrimitiveGroup*>( it.group() ); if ( group->getInternal() || group->isEmpty() ) { continue; } const UT_String &groupName = group->getName(); if ( groupName.startsWith( tagGroupPrefix ) && group->containsAny( prims ) ) { UT_String tag; groupName.substr( tag, tagGroupPrefix.length() ); tag.substitute( "_", ":" ); tags.push_back( tag.buffer() ); } } } } } }
bool HoudiniScene::hasTag( const Name &name, bool includeChildren ) const { const OP_Node *node = retrieveNode(); if ( !node ) { return false; } // check for user supplied tags if we're not inside a SOP if ( !m_contentIndex && node->hasParm( pTags.getToken() ) ) { UT_String parmTags; node->evalString( parmTags, pTags.getToken(), 0, 0 ); if ( UT_String( name.c_str() ).multiMatch( parmTags ) ) { return true; } } // check with the registered tag readers std::vector<CustomTagReader> &tagReaders = customTagReaders(); for ( std::vector<CustomTagReader>::const_iterator it = tagReaders.begin(); it != tagReaders.end(); ++it ) { if ( it->m_has( node, name ) ) { return true; } } // check tags based on primitive groups OBJ_Node *contentNode = retrieveNode( true )->castToOBJNode(); if ( contentNode && contentNode->getObjectType() == OBJ_GEOMETRY && m_splitter ) { GU_DetailHandle newHandle = m_splitter->split( contentPathValue() ); if ( !newHandle.isNull() ) { GU_DetailHandleAutoReadLock readHandle( newHandle ); if ( const GU_Detail *geo = readHandle.getGdp() ) { GA_Range prims = geo->getPrimitiveRange(); for ( GA_GroupTable::iterator<GA_ElementGroup> it=geo->primitiveGroups().beginTraverse(); !it.atEnd(); ++it ) { GA_PrimitiveGroup *group = static_cast<GA_PrimitiveGroup*>( it.group() ); if ( group->getInternal() || group->isEmpty() ) { continue; } const UT_String &groupName = group->getName(); if ( groupName.startsWith( tagGroupPrefix ) && group->containsAny( prims ) ) { UT_String tag; groupName.substr( tag, tagGroupPrefix.length() ); tag.substitute( "_", ":" ); if ( tag.equal( name.c_str() ) ) { return true; } } } } } } return false; }
ObjectPtr FromHoudiniGroupConverter::doConversion( ConstCompoundObjectPtr operands ) const { GroupPtr result = new Group(); if ( operands->member<const IntData>( "groupingMode" )->readable() == NameAttribute ) { DetailSplitterPtr splitter = new DetailSplitter( handle() ); std::vector<std::string> children; splitter->values( children ); if ( children.empty() ) { doUnnamedConversion( GU_DetailHandleAutoReadLock( handle() ).getGdp(), result, operands ); return result; } for ( std::vector<std::string>::iterator it = children.begin(); it != children.end(); ++it ) { const std::string &name = *it; GU_DetailHandle childHandle = splitter->split( name ); if ( childHandle.isNull() ) { continue; } GU_DetailHandleAutoReadLock readHandle( childHandle ); const GU_Detail *childGeo = readHandle.getGdp(); ObjectPtr child = doDetailConversion( childGeo, operands ); if ( !child ) { // this happens when mismatched primitives share the same name doUnnamedConversion( childGeo, result, operands, name ); } else if ( VisibleRenderablePtr renderable = IECore::runTimeCast<VisibleRenderable>( child ) ) { if ( name != "" ) { renderable->blindData()->member<StringData>( "name", false, true )->writable() = name; } result->addChild( renderable ); } } } else { GU_DetailHandleAutoReadLock readHandle( handle() ); const GU_Detail *geo = readHandle.getGdp(); if ( !geo ) { return 0; } size_t numResultPrims = 0; size_t numOrigPrims = geo->getNumPrimitives(); for ( GA_GroupTable::iterator<GA_ElementGroup> it=geo->primitiveGroups().beginTraverse(); !it.atEnd(); ++it ) { GA_PrimitiveGroup *group = static_cast<GA_PrimitiveGroup*>( it.group() ); if ( group->getInternal() || group->isEmpty() ) { continue; } VisibleRenderablePtr renderable = 0; numResultPrims += doGroupConversion( geo, group, renderable, operands ); if( !renderable ) { continue; } renderable->blindData()->member<StringData>( "name", false, true )->writable() = group->getName().toStdString(); result->addChild( renderable ); } if ( numOrigPrims == numResultPrims ) { return result; } GU_Detail ungroupedGeo( (GU_Detail*)geo ); GA_PrimitiveGroup *ungrouped = static_cast<GA_PrimitiveGroup*>( ungroupedGeo.createInternalElementGroup( GA_ATTRIB_PRIMITIVE, "FromHoudiniGroupConverter__ungroupedPrimitives" ) ); for ( GA_GroupTable::iterator<GA_ElementGroup> it=geo->primitiveGroups().beginTraverse(); !it.atEnd(); ++it ) { *ungrouped |= *static_cast<GA_PrimitiveGroup*>( it.group() ); } ungrouped->toggleRange( ungroupedGeo.getPrimitiveRange() ); if ( ungrouped->isEmpty() ) { return result; } VisibleRenderablePtr renderable = 0; doGroupConversion( &ungroupedGeo, ungrouped, renderable, operands ); if ( renderable ) { result->addChild( renderable ); } } return result; }
//Do the interpolation calculations bool SIM_SnowSolver::solveGasSubclass(SIM_Engine &engine, SIM_Object *obj, SIM_Time time, SIM_Time framerate){ /// STEP #0: Retrieve all data objects from Houdini //Scalar params freal particle_mass = getPMass(); freal YOUNGS_MODULUS = getYoungsModulus(); freal POISSONS_RATIO = getPoissonsRatio(); freal CRIT_COMPRESS = getCritComp(); freal CRIT_STRETCH = getCritStretch(); freal FLIP_PERCENT = getFlipPercent(); freal HARDENING = getHardening(); freal CFL = getCfl(); freal COF = getCof(); freal division_size = getDivSize(); freal max_vel = getMaxVel(); //Vector params vector3 GRAVITY = getGravity(); vector3 bbox_min_limit = getBboxMin(); vector3 bbox_max_limit = getBboxMax(); //Particle params UT_String s_p, s_vol, s_den, s_vel, s_fe, s_fp; getParticles(s_p); getPVol(s_vol); getPD(s_den); getPVel(s_vel); getPFe(s_fe); getPFp(s_fp); SIM_Geometry* geometry = (SIM_Geometry*) obj->getNamedSubData(s_p); if (!geometry) return true; //Get particle data //Do we use the attribute name??? // GU_DetailHandle gdh = geometry->getGeometry().getWriteableCopy(); GU_DetailHandle gdh = geometry->getOwnGeometry(); const GU_Detail* gdp_in = gdh.readLock(); // Must unlock later GU_Detail* gdp_out = gdh.writeLock(); GA_RWAttributeRef p_ref_position = gdp_out->findPointAttribute("P"); GA_RWHandleT<vector3> p_position(p_ref_position.getAttribute()); GA_RWAttributeRef p_ref_volume = gdp_out->findPointAttribute(s_vol); GA_RWHandleT<freal> p_volume(p_ref_volume.getAttribute()); GA_RWAttributeRef p_ref_density = gdp_out->findPointAttribute(s_den); GA_RWHandleT<freal> p_density(p_ref_density.getAttribute()); GA_RWAttributeRef p_ref_vel = gdp_out->findPointAttribute(s_vel); GA_RWHandleT<vector3> p_vel(p_ref_vel.getAttribute()); GA_RWAttributeRef p_ref_Fe = gdp_out->findPointAttribute(s_fe); GA_RWHandleT<matrix3> p_Fe(p_ref_Fe.getAttribute()); GA_RWAttributeRef p_ref_Fp = gdp_out->findPointAttribute(s_fp); GA_RWHandleT<matrix3> p_Fp(p_ref_Fp.getAttribute()); //EVALUATE PARAMETERS freal mu = YOUNGS_MODULUS/(2+2*POISSONS_RATIO); freal lambda = YOUNGS_MODULUS*POISSONS_RATIO/((1+POISSONS_RATIO)*(1-2*POISSONS_RATIO)); //Get grid data SIM_ScalarField *g_mass_field; SIM_DataArray g_mass_data; getMatchingData(g_mass_data, obj, MPM_G_MASS); g_mass_field = SIM_DATA_CAST(g_mass_data(0), SIM_ScalarField); SIM_VectorField *g_nvel_field; SIM_DataArray g_nvel_data; getMatchingData(g_nvel_data, obj, MPM_G_NVEL); g_nvel_field = SIM_DATA_CAST(g_nvel_data(0), SIM_VectorField); SIM_VectorField *g_ovel_field; SIM_DataArray g_ovel_data; getMatchingData(g_ovel_data, obj, MPM_G_OVEL); g_ovel_field = SIM_DATA_CAST(g_ovel_data(0), SIM_VectorField); SIM_ScalarField *g_active_field; SIM_DataArray g_active_data; getMatchingData(g_active_data, obj, MPM_G_ACTIVE); g_active_field = SIM_DATA_CAST(g_active_data(0), SIM_ScalarField); SIM_ScalarField *g_density_field; SIM_DataArray g_density_data; getMatchingData(g_density_data, obj, MPM_G_DENSITY); g_density_field = SIM_DATA_CAST(g_density_data(0), SIM_ScalarField); SIM_ScalarField *g_col_field; SIM_DataArray g_col_data; getMatchingData(g_col_data, obj, MPM_G_COL); g_col_field = SIM_DATA_CAST(g_col_data(0), SIM_ScalarField); SIM_VectorField *g_colVel_field; SIM_DataArray g_colVel_data; getMatchingData(g_colVel_data, obj, MPM_G_COLVEL); g_colVel_field = SIM_DATA_CAST(g_colVel_data(0), SIM_VectorField); SIM_VectorField *g_extForce_field; SIM_DataArray g_extForce_data; getMatchingData(g_extForce_data, obj, MPM_G_EXTFORCE); g_extForce_field = SIM_DATA_CAST(g_extForce_data(0), SIM_VectorField); UT_VoxelArrayF *g_mass = g_mass_field->getField()->fieldNC(), *g_nvelX = g_nvel_field->getField(0)->fieldNC(), *g_nvelY = g_nvel_field->getField(1)->fieldNC(), *g_nvelZ = g_nvel_field->getField(2)->fieldNC(), *g_ovelX = g_ovel_field->getField(0)->fieldNC(), *g_ovelY = g_ovel_field->getField(1)->fieldNC(), *g_ovelZ = g_ovel_field->getField(2)->fieldNC(), *g_colVelX = g_colVel_field->getField(0)->fieldNC(), *g_colVelY = g_colVel_field->getField(1)->fieldNC(), *g_colVelZ = g_colVel_field->getField(2)->fieldNC(), *g_extForceX = g_extForce_field->getField(0)->fieldNC(), *g_extForceY = g_extForce_field->getField(1)->fieldNC(), *g_extForceZ = g_extForce_field->getField(2)->fieldNC(), *g_col = g_col_field->getField()->fieldNC(), *g_active = g_active_field->getField()->fieldNC(); int point_count = gdp_out->getPointRange().getEntries(); std::vector<boost::array<freal,64> > p_w(point_count); std::vector<boost::array<vector3,64> > p_wgh(point_count); //Get world-to-grid conversion ratios //Particle's grid position can be found via (pos - grid_origin)/voxel_dims vector3 voxel_dims = g_mass_field->getVoxelSize(), grid_origin = g_mass_field->getOrig(), grid_divs = g_mass_field->getDivisions(); //Houdini uses voxel centers for grid nodes, rather than grid corners grid_origin += voxel_dims/2.0; freal voxelArea = voxel_dims[0]*voxel_dims[1]*voxel_dims[2]; /* //Reset grid for(int iX=0; iX < grid_divs[0]; iX++){ for(int iY=0; iY < grid_divs[1]; iY++){ for(int iZ=0; iZ < grid_divs[2]; iZ++){ g_mass->setValue(iX,iY,iZ,0); g_active->setValue(iX,iY,iZ,0); g_ovelX->setValue(iX,iY,iZ,0); g_ovelY->setValue(iX,iY,iZ,0); g_ovelZ->setValue(iX,iY,iZ,0); g_nvelX->setValue(iX,iY,iZ,0); g_nvelY->setValue(iX,iY,iZ,0); g_nvelZ->setValue(iX,iY,iZ,0); } } } */ /// STEP #1: Transfer mass to grid if (p_position.isValid()){ //Iterate through particles for (GA_Iterator it(gdp_out->getPointRange()); !it.atEnd(); it.advance()){ int pid = it.getOffset(); //Get grid position vector3 gpos = (p_position.get(pid) - grid_origin)/voxel_dims; int p_gridx = (int) gpos[0], p_gridy = (int) gpos[1], p_gridz = (int) gpos[2]; //g_mass_field->posToIndex(p_position.get(pid),p_gridx,p_gridy,p_gridz); freal particle_density = p_density.get(pid); //Compute weights and transfer mass for (int idx=0, z=p_gridz-1, z_end=z+3; z<=z_end; z++){ //Z-dimension interpolation freal z_pos = gpos[2]-z, wz = SIM_SnowSolver::bspline(z_pos), dz = SIM_SnowSolver::bsplineSlope(z_pos); for (int y=p_gridy-1, y_end=y+3; y<=y_end; y++){ //Y-dimension interpolation freal y_pos = gpos[1]-y, wy = SIM_SnowSolver::bspline(y_pos), dy = SIM_SnowSolver::bsplineSlope(y_pos); for (int x=p_gridx-1, x_end=x+3; x<=x_end; x++, idx++){ //X-dimension interpolation freal x_pos = gpos[0]-x, wx = SIM_SnowSolver::bspline(x_pos), dx = SIM_SnowSolver::bsplineSlope(x_pos); //Final weight is dyadic product of weights in each dimension freal weight = wx*wy*wz; p_w[pid-1][idx] = weight; //Weight gradient is a vector of partial derivatives p_wgh[pid-1][idx] = vector3(dx*wy*wz, wx*dy*wz, wx*wy*dz)/voxel_dims; //Interpolate mass freal node_mass = g_mass->getValue(x,y,z); node_mass += weight*particle_mass; g_mass->setValue(x,y,z,node_mass); } } } } } /// STEP #2: First timestep only - Estimate particle volumes using grid mass /* if (time == 0.0){ //Iterate through particles for (GA_Iterator it(gdp_out->getPointRange()); !it.atEnd(); it.advance()){ int pid = it.getOffset(); freal density = 0; //Get grid position int p_gridx = 0, p_gridy = 0, p_gridz = 0; vector3 gpos = (p_position.get(pid) - grid_origin)/voxel_dims; int p_gridx = (int) gpos[0], p_gridy = (int) gpos[1], p_gridz = (int) gpos[2]; //g_nvel_field->posToIndex(0,p_position.get(pid),p_gridx,p_gridy,p_gridz); //Transfer grid density (within radius) to particles for (int idx=0, z=p_gridz-1, z_end=z+3; z<=z_end; z++){ for (int y=p_gridy-1, y_end=y+3; y<=y_end; y++){ for (int x=p_gridx-1, x_end=x+3; x<=x_end; x++, idx++){ freal w = p_w[pid-1][idx]; if (w > EPSILON){ //Transfer density density += w * g_mass->getValue(x,y,z); } } } } density /= voxelArea; p_density.set(pid,density); p_volume.set(pid, particle_mass/density); } } //*/ /// STEP #3: Transfer velocity to grid //This must happen after transferring mass, to conserve momentum //Iterate through particles and transfer for (GA_Iterator it(gdp_in->getPointRange()); !it.atEnd(); it.advance()){ int pid = it.getOffset(); vector3 vel_fac = p_vel.get(pid)*particle_mass; //Get grid position vector3 gpos = (p_position.get(pid) - grid_origin)/voxel_dims; int p_gridx = (int) gpos[0], p_gridy = (int) gpos[1], p_gridz = (int) gpos[2]; //g_nvel_field->posToIndex(0,p_position.get(pid),p_gridx,p_gridy,p_gridz); //Transfer to grid nodes within radius for (int idx=0, z=p_gridz-1, z_end=z+3; z<=z_end; z++){ for (int y=p_gridy-1, y_end=y+3; y<=y_end; y++){ for (int x=p_gridx-1, x_end=x+3; x<=x_end; x++, idx++){ freal w = p_w[pid-1][idx]; if (w > EPSILON){ freal nodex_vel = g_ovelX->getValue(x,y,z) + vel_fac[0]*w; freal nodey_vel = g_ovelY->getValue(x,y,z) + vel_fac[1]*w; freal nodez_vel = g_ovelZ->getValue(x,y,z) + vel_fac[2]*w; g_ovelX->setValue(x,y,z,nodex_vel); g_ovelY->setValue(x,y,z,nodey_vel); g_ovelZ->setValue(x,y,z,nodez_vel); g_active->setValue(x,y,z,1.0); } } } } } //Division is slow (maybe?); we only want to do divide by mass once, for each active node for(int iX=0; iX < grid_divs[0]; iX++){ for(int iY=0; iY < grid_divs[1]; iY++){ for(int iZ=0; iZ < grid_divs[2]; iZ++){ //Only check nodes that have mass if (g_active->getValue(iX,iY,iZ)){ freal node_mass = 1/(g_mass->getValue(iX,iY,iZ)); g_ovelX->setValue(iX,iY,iZ,(g_ovelX->getValue(iX,iY,iZ)*node_mass)); g_ovelY->setValue(iX,iY,iZ,(g_ovelY->getValue(iX,iY,iZ)*node_mass)); g_ovelZ->setValue(iX,iY,iZ,(g_ovelZ->getValue(iX,iY,iZ)*node_mass)); } } } } /// STEP #4: Compute new grid velocities //Temporary variables for plasticity and force calculation //We need one set of variables for each thread that will be running eigen_matrix3 def_elastic, def_plastic, energy, svd_u, svd_v; Eigen::JacobiSVD<eigen_matrix3, Eigen::NoQRPreconditioner> svd; eigen_vector3 svd_e; matrix3 HDK_def_plastic, HDK_def_elastic, HDK_energy; freal* data_dp = HDK_def_plastic.data(); freal* data_de = HDK_def_elastic.data(); freal* data_energy = HDK_energy.data(); //Map Eigen matrices to HDK matrices Eigen::Map<eigen_matrix3> data_dp_map(data_dp); Eigen::Map<eigen_matrix3> data_de_map(data_de); Eigen::Map<eigen_matrix3> data_energy_map(data_energy); //Compute force at each particle and transfer to Eulerian grid //We use "nvel" to hold the grid force, since that variable is not in use for (GA_Iterator it(gdp_in->getPointRange()); !it.atEnd(); it.advance()){ int pid = it.getOffset(); //Apply plasticity to deformation gradient, before computing forces //We need to use the Eigen lib to do the SVD; transfer houdini matrices to Eigen matrices HDK_def_plastic = p_Fp.get(pid); HDK_def_elastic = p_Fe.get(pid); def_plastic = Eigen::Map<eigen_matrix3>(data_dp); def_elastic = Eigen::Map<eigen_matrix3>(data_de); //Compute singular value decomposition (uev*) svd.compute(def_elastic, Eigen::ComputeFullV | Eigen::ComputeFullU); svd_e = svd.singularValues(); svd_u = svd.matrixU(); svd_v = svd.matrixV(); //Clamp singular values for (int i=0; i<3; i++){ if (svd_e[i] < CRIT_COMPRESS) svd_e[i] = CRIT_COMPRESS; else if (svd_e[i] > CRIT_STRETCH) svd_e[i] = CRIT_STRETCH; } //Put SVD back together for new elastic and plastic gradients def_plastic = svd_v * svd_e.asDiagonal().inverse() * svd_u.transpose() * def_elastic * def_plastic; svd_v.transposeInPlace(); def_elastic = svd_u * svd_e.asDiagonal() * svd_v; //Now compute the energy partial derivative (which we use to get force at each grid node) energy = 2*mu*(def_elastic - svd_u*svd_v)*def_elastic.transpose(); //Je is the determinant of def_elastic (equivalent to svd_e.prod()) freal Je = svd_e.prod(), contour = lambda*Je*(Je-1), jp = def_plastic.determinant(), particle_vol = p_volume.get(pid); for (int i=0; i<3; i++) energy(i,i) += contour; energy *= particle_vol * exp(HARDENING*(1-jp)); //Transfer Eigen matrices back to HDK data_dp_map = def_plastic; data_de_map = def_elastic; data_energy_map = energy; p_Fp.set(pid,HDK_def_plastic); p_Fe.set(pid,HDK_def_elastic); //Transfer energy to surrounding grid nodes vector3 gpos = (p_position.get(pid) - grid_origin)/voxel_dims; int p_gridx = (int) gpos[0], p_gridy = (int) gpos[1], p_gridz = (int) gpos[2]; for (int idx=0, z=p_gridz-1, z_end=z+3; z<=z_end; z++){ for (int y=p_gridy-1, y_end=y+3; y<=y_end; y++){ for (int x=p_gridx-1, x_end=x+3; x<=x_end; x++, idx++){ freal w = p_w[pid-1][idx]; if (w > EPSILON){ vector3 ngrad = p_wgh[pid-1][idx]; g_nvelX->setValue(x,y,z,g_nvelX->getValue(x,y,z) + ngrad.dot(HDK_energy[0])); g_nvelY->setValue(x,y,z,g_nvelY->getValue(x,y,z) + ngrad.dot(HDK_energy[1])); g_nvelZ->setValue(x,y,z,g_nvelZ->getValue(x,y,z) + ngrad.dot(HDK_energy[2])); } } } } } //Use new forces to solve for new velocities for(int iX=0; iX < grid_divs[0]; iX++){ for(int iY=0; iY < grid_divs[1]; iY++){ for(int iZ=0; iZ < grid_divs[2]; iZ++){ //Only compute for active nodes if (g_active->getValue(iX,iY,iZ)){ freal nodex_ovel = g_ovelX->getValue(iX,iY,iZ); freal nodey_ovel = g_ovelY->getValue(iX,iY,iZ); freal nodez_ovel = g_ovelZ->getValue(iX,iY,iZ); freal forcex = g_nvelX->getValue(iX,iY,iZ); freal forcey = g_nvelY->getValue(iX,iY,iZ); freal forcez = g_nvelZ->getValue(iX,iY,iZ); freal node_mass = 1/(g_mass->getValue(iX,iY,iZ)); freal ext_forceX = GRAVITY[0] + g_extForceX->getValue(iX,iY,iZ); freal ext_forceY = GRAVITY[1] + g_extForceY->getValue(iX,iY,iZ); freal ext_forceZ = GRAVITY[2] + g_extForceZ->getValue(iX,iY,iZ); nodex_ovel += framerate*(ext_forceX - forcex*node_mass); nodey_ovel += framerate*(ext_forceY - forcey*node_mass); nodez_ovel += framerate*(ext_forceZ - forcez*node_mass); //Limit velocity to max_vel vector3 g_nvel(nodex_ovel, nodey_ovel, nodez_ovel); freal nvelNorm = g_nvel.length(); if(nvelNorm > max_vel){ freal velRatio = max_vel/nvelNorm; g_nvel*= velRatio; } g_nvelX->setValue(iX,iY,iZ,g_nvel[0]); g_nvelY->setValue(iX,iY,iZ,g_nvel[1]); g_nvelZ->setValue(iX,iY,iZ,g_nvel[2]); } } } } /// STEP #5: Grid collision resolution vector3 sdf_normal; //* for(int iX=1; iX < grid_divs[0]-1; iX++){ for(int iY=1; iY < grid_divs[1]-1; iY++){ for(int iZ=1; iZ < grid_divs[2]-1; iZ++){ if (g_active->getValue(iX,iY,iZ)){ if (!computeSDFNormal(g_col, iX, iY, iZ, sdf_normal)) continue; //Collider velocity vector3 vco( g_colVelX->getValue(iX,iY,iZ), g_colVelY->getValue(iX,iY,iZ), g_colVelZ->getValue(iX,iY,iZ) ); //Grid velocity vector3 v( g_nvelX->getValue(iX,iY,iZ), g_nvelY->getValue(iX,iY,iZ), g_nvelZ->getValue(iX,iY,iZ) ); //Skip if bodies are separating vector3 vrel = v - vco; freal vn = vrel.dot(sdf_normal); if (vn >= 0) continue; //Resolve collisions; also add velocity of collision object to snow velocity //Sticks to surface (too slow to overcome static friction) vector3 vt = vrel - (sdf_normal*vn); freal stick = vn*COF, vt_norm = vt.length(); if (vt_norm <= -stick) vt = vco; //Dynamic friction else vt += stick*vt/vt_norm + vco; g_nvelX->setValue(iX,iY,iZ,vt[0]); g_nvelY->setValue(iX,iY,iZ,vt[1]); g_nvelZ->setValue(iX,iY,iZ,vt[2]); } } } } //*/ /// STEP #6: Transfer grid velocities to particles and integrate /// STEP #7: Particle collision resolution vector3 pic, flip, col_vel; matrix3 vel_grad; //Iterate through particles for (GA_Iterator it(gdp_in->getPointRange()); !it.atEnd(); it.advance()){ int pid = it.getOffset(); //Particle position vector3 pos(p_position.get(pid)); //Reset velocity pic[0] = 0.0; pic[1] = 0.0; pic[2] = 0.0; flip = p_vel.get(pid); vel_grad.zero(); freal density = 0; //Get grid position vector3 gpos = (pos - grid_origin)/voxel_dims; int p_gridx = (int) gpos[0], p_gridy = (int) gpos[1], p_gridz = (int) gpos[2]; for (int idx=0, z=p_gridz-1, z_end=z+3; z<=z_end; z++){ for (int y=p_gridy-1, y_end=y+3; y<=y_end; y++){ for (int x=p_gridx-1, x_end=x+3; x<=x_end; x++, idx++){ freal w = p_w[pid-1][idx]; if (w > EPSILON){ const vector3 node_wg = p_wgh[pid-1][idx]; const vector3 node_nvel( g_nvelX->getValue(x,y,z), g_nvelY->getValue(x,y,z), g_nvelZ->getValue(x,y,z) ); //Transfer velocities pic += node_nvel*w; flip[0] += (node_nvel[0] - g_ovelX->getValue(x,y,z))*w; flip[1] += (node_nvel[1]- g_ovelY->getValue(x,y,z))*w; flip[2] += (node_nvel[2] - g_ovelZ->getValue(x,y,z))*w; //Transfer density density += w * g_mass->getValue(x,y,z); //Transfer veloctiy gradient vel_grad.outerproductUpdate(1.0, node_nvel, node_wg); } } } } //Finalize velocity update vector3 vel = flip*FLIP_PERCENT + pic*(1-FLIP_PERCENT); //Reset collision data freal col_sdf = 0; sdf_normal[0] = 0; sdf_normal[1] = 0; sdf_normal[2] = 0; col_vel[0] = 0; col_vel[1] = 0; col_vel[2] = 0; //Interpolate surrounding nodes' SDF info to the particle (trilinear interpolation) for (int idx=0, z=p_gridz, z_end=z+1; z<=z_end; z++){ freal w_z = gpos[2]-z; for (int y=p_gridy, y_end=y+1; y<=y_end; y++){ freal w_zy = w_z*(gpos[1]-y); for (int x=p_gridx, x_end=x+1; x<=x_end; x++, idx++){ freal weight = fabs(w_zy*(gpos[0]-x)); //cout << w_zy << "," << (gpos[0]-x) << "," << weight << endl; vector3 temp_normal; computeSDFNormal(g_col, x, y, z, temp_normal); //goto SKIP_PCOLLIDE; //cout << g_col->getValue(x, y, z) << endl; //Interpolate sdf_normal += temp_normal*weight; col_sdf += g_col->getValue(x, y, z)*weight; col_vel[0] += g_colVelX->getValue(x, y, z)*weight; col_vel[1] += g_colVelY->getValue(x, y, z)*weight; col_vel[2] += g_colVelZ->getValue(x, y, z)*weight; } } } //Resolve particle collisions //cout << col_sdf << endl; if (col_sdf > 0){ vector3 vrel = vel - col_vel; freal vn = vrel.dot(sdf_normal); //Skip if bodies are separating if (vn < 0){ //Resolve and add velocity of collision object to snow velocity //Sticks to surface (too slow to overcome static friction) vel = vrel - (sdf_normal*vn); freal stick = vn*COF, vel_norm = vel.length(); if (vel_norm <= -stick) vel = col_vel; //Dynamic friction else vel += stick*vel/vel_norm + col_vel; } } SKIP_PCOLLIDE: //Finalize density update density /= voxelArea; p_density.set(pid,density); //Update particle position pos += framerate*vel; //Limit particle position int mask = 0; /* for (int i=0; i<3; i++){ if (pos[i] > bbox_max_limit[i]){ pos[i] = bbox_max_limit[i]; vel[i] = 0.0; mask |= 1 << i; } else if (pos[i] < bbox_min_limit[i]){ pos[i] = bbox_min_limit[i]; vel[i] = 0.0; mask |= 1 << i; } } //Slow particle down at bounds (not really necessary...) if (mask){ for (int i=0; i<3; i++){ if (mask & 0x1) vel[i] *= .05; mask >>= 1; } }//*/ p_vel.set(pid,vel); p_position.set(pid,pos); //Update particle deformation gradient //Note: plasticity is computed on the next timestep... vel_grad *= framerate; vel_grad(0,0) += 1; vel_grad(1,1) += 1; vel_grad(2,2) += 1; p_Fe.set(pid, vel_grad*p_Fe.get(pid)); } gdh.unlock(gdp_out); gdh.unlock(gdp_in); return true; }