void SOP_FlexSolver::copySourceParticles() { if (mySource) { for (GA_Offset srcptoff = 0; srcptoff < maxParticles; ++srcptoff) { const UT_Vector3 pos = mySource->getPos3(srcptoff); UT_Vector3 vel; if (mySourceVel.isValid()) vel = mySourceVel.get(srcptoff); else vel = UT_Vector3(0,0,0); uint index = static_cast<int>(srcptoff); uint p = index * 4; uint v = index * 3; particles[p] = pos.x(); particles[p+1] = pos.y(); particles[p+2] = pos.z(); particles[p+3] = 1.0; velocities[v] = vel.x(); velocities[v+1] = vel.y(); velocities[v+2] = vel.z(); gdp->insertPointCopy(srcptoff); gdp->setPos3(srcptoff, pos); } } }
void SOP_FlexSolver::timeStep(fpreal now) { UT_Vector3 force(FX(now), FY(now), FZ(now)); // int nbirth = BIRTH(now); if (error() >= UT_ERROR_ABORT) return; for (GA_Offset srcptoff = 0; srcptoff < maxParticles; ++srcptoff) { UT_Vector3 vel; if (mySourceVel.isValid()) vel = mySourceVel.get(srcptoff); else vel = UT_Vector3(0,0,0); vel += force; uint index = static_cast<int>(srcptoff); uint v = index * 3; velocities[v] = vel.x(); velocities[v+1] = vel.y(); velocities[v+2] = vel.z(); } InitFlexParams(*myParms, now); flexSetParams(mySolver, myParms); flexSetVelocities(mySolver, &velocities[0], maxParticles, eFlexMemoryHost); const float dt = 1.0 / 24.0; const int substeps = 1; // tick solver flexUpdateSolver(mySolver, dt, substeps, myTimer); // update GPU data asynchronously flexGetParticles(mySolver, (float*)&particles[0], maxParticles, eFlexMemoryHost); for (GA_Offset srcptoff = 0; srcptoff < maxParticles; ++srcptoff) { uint p = static_cast<int>(srcptoff) * 4; const UT_Vector3 pos = UT_Vector3(particles[p], particles[p+1], particles[p+2]); gdp->setPos3(srcptoff, pos); } }
static void exportParticlesDetail( const GU_Detail* gdp, const std::string& filePath, const std::map<std::string, channel_type>& desiredChannels ) { prt_ofstream ostream; static std::map<std::string, std::string> s_reservedChannels; if( s_reservedChannels.empty() ) { s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_NORMAL ) ] = "Normal"; s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_TEXTURE ) ] = "TextureCoord"; s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_VELOCITY ) ] = "Velocity"; s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_DIFFUSE ) ] = "Color"; //s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ALPHA ) ] = "Density"; //s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_MASS ) ] = "Density"; s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) ] = ""; s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ID ) ] = "ID"; s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_PSCALE ) ] = "Scale"; s_reservedChannels[ "accel" ] = "Acceleration"; } float posVal[3]; float lifeVal[2]; ostream.bind( "Position", posVal, 3 ); //We handle the life channel in a special manner GA_ROAttributeRef lifeAttrib = gdp->findPointAttribute( gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) ); if( lifeAttrib.isValid() ){ std::map<std::string,channel_type>::const_iterator it; it = desiredChannels.find( "Age" ); if( it != desiredChannels.end() && it->second.second == 1 ) ostream.bind( "Age", &lifeVal[0], 1, it->second.first ); else if( desiredChannels.empty() ) ostream.bind( "Age", &lifeVal[0], 1, prtio::data_types::type_float16 ); it = desiredChannels.find( "LifeSpan" ); if( it != desiredChannels.end() && it->second.second == 1 ) ostream.bind( "LifeSpan", &lifeVal[1], 1, it->second.first ); else if( desiredChannels.empty() ) ostream.bind( "LifeSpan", &lifeVal[1], 1, prtio::data_types::type_float16 ); } //Using a deque to prevent the memory from moving around after adding the bound_attribute to the container. std::deque< bound_attribute<int> > m_intAttrs; std::deque< bound_attribute<float> > m_floatAttrs; std::deque< bound_attribute<float> > m_vectorAttrs; for ( GA_AttributeDict::iterator it = gdp->getAttributes().getDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it) { GA_Attribute *node = it.attrib(); std::string channelName = node->getName(); //Translate special names std::map<std::string,std::string>::const_iterator itResChannel = s_reservedChannels.find( channelName ); if( itResChannel != s_reservedChannels.end() ){ //If its empty, that means we reserve some sort of special handling. if( itResChannel->second.empty() ) continue; channelName = itResChannel->second; } //Skip channels that aren't on the list. std::map<std::string,channel_type>::const_iterator itChannel = desiredChannels.find( channelName ); bool channelIsDesired = ( itChannel != desiredChannels.end() ); if( !desiredChannels.empty() && !channelIsDesired ) continue; prtio::data_types::enum_t type; //Only add valid channel names if( detail::is_valid_channel_name( channelName.c_str() ) ) { //I add the new item to the deque, THEN initialize it since a deque will not move the object around and this allows //me to allocate the float array and not have to worry about the object getting deleted too early. switch( node->getStorageClass() ){ case GA_STORECLASS_FLOAT: if( node->getTupleSize()==3 ){ m_vectorAttrs.push_back( bound_attribute<float>() ); m_vectorAttrs.back().attr = gdp->findPointAttribute(node->getName()); m_vectorAttrs.back().count = node->getTupleSize(); m_vectorAttrs.back().data = new float[m_vectorAttrs.back().count]; type = prtio::data_types::type_float16; if( channelIsDesired ){ type = itChannel->second.first; if( itChannel->second.second != m_vectorAttrs.back().count ) continue; } ostream.bind( channelName, m_vectorAttrs.back().data, m_vectorAttrs.back().count, type ); } else { m_floatAttrs.push_back( bound_attribute<float>() ); m_floatAttrs.back().attr = gdp->findPointAttribute( node->getName() ); m_floatAttrs.back().count = node->getTupleSize(); m_floatAttrs.back().data = new float[m_floatAttrs.back().count]; type = prtio::data_types::type_float16; if( channelIsDesired ){ type = itChannel->second.first; if( itChannel->second.second != m_floatAttrs.back().count ) continue; } ostream.bind( channelName, m_floatAttrs.back().data, m_floatAttrs.back().count, type ); } break; case GA_STORECLASS_INT: m_intAttrs.push_back( bound_attribute<int>() ); m_intAttrs.back().attr = gdp->findPointAttribute( node->getName() ); m_intAttrs.back().count = node->getTupleSize(); m_intAttrs.back().data = new int[m_intAttrs.back().count]; type = prtio::data_types::type_int32; if( channelIsDesired ){ type = itChannel->second.first; if( itChannel->second.second != m_intAttrs.back().count ) continue; } ostream.bind( channelName, m_intAttrs.back().data, m_intAttrs.back().count, type ); break; default: break; } } } try{ ostream.open( filePath ); } catch( const std::ios::failure& e ) { std::cerr << e.what() << std::endl; throw HOM_OperationFailed( "Failed to open the file" ); } GA_IndexMap map = gdp->getPointMap(); UT_Vector3 p; GEO_Point* pt; GA_Index indexSize = map.indexSize(); GA_Offset offset; for( int i = 0 ; i < indexSize; i++ ) { offset = map.offsetFromIndex( i ); p = gdp->getPos3( offset ); posVal[0] = p.x(); posVal[1] = p.y(); posVal[2] = -1 * p.z(); //TODO: Remove the GEO_Point object that is now deprecated. pt = ( GEO_Point* )gdp->getGBPoint( offset ); //TODO: Convert this into appropriate time values. Is it seconds or frames or what?! if( lifeAttrib.isValid() ) pt->get( lifeAttrib, lifeVal, 2 ); for( std::deque< bound_attribute<float> >::iterator it = m_floatAttrs.begin(), itEnd = m_floatAttrs.end(); it != itEnd; ++it ) pt->get( it->attr, it->data, it->count ); for( std::deque< bound_attribute<float> >::iterator it = m_vectorAttrs.begin(), itEnd = m_vectorAttrs.end(); it != itEnd; ++it ) { pt->get( it->attr, it->data, it->count ); //TODO: Optionally transform into some consistent world space for PRT files. } for( std::deque< bound_attribute<int> >::iterator it = m_intAttrs.begin(), itEnd = m_intAttrs.end(); it != itEnd; ++it ) pt->get( it->attr, it->data, it->count ); ostream.write_next_particle(); } ostream.close(); }
void GR_rmanPtc::renderWire( GU_Detail *gdp, RE_Render &ren, const GR_AttribOffset &ptinfo, const GR_DisplayOption *dopt, float lod, const GU_PrimGroupClosure *hidden_geometry ) { int i, nprim; GEO_Primitive *prim; UT_Vector3 v3; rmanPtcSop::rmanPtcDetail *detail = dynamic_cast<rmanPtcSop::rmanPtcDetail*>(gdp); if ( !detail ) return; // rebuild our display list if ( detail->redraw ) { srand(0); GEO_PointList &points = detail->points(); int display_channel = detail->display_channel; // render as points GEO_Point *pt = 0; UT_Vector4 pos; float col[3] = {1.0,1.0,1.0}; if ( !detail->use_disk ) { ren.pushPointSize(detail->point_size); ren.beginPoint(); } for ( unsigned int i=0; i<points.entries(); ++i ) { if ( rand()/(float)RAND_MAX<=detail->display_probability ) { // point position pt = points[i]; pos = pt->getPos(); // display colour float *ptr = NULL; if (detail->attributes.size() >0) { ptr = pt->castAttribData<float>( detail->attributes[display_channel] ); if (ptr) { if ( detail->attribute_size[display_channel]==1) col[0] = col[1] = col[2] = ptr[0]; else { col[0] = ptr[0]; col[1] = ptr[1]; col[2] = ptr[2]; } } } // draw point if ( !detail->use_cull_bbox || detail->cull_bbox.isInside( pos ) ) { if ( !detail->use_disk ) { // render as points ren.setColor( col[0], col[1], col[2], 1 ); ren.vertex3DW( pos.x(), pos.y(), pos.z() ); } else { // render as disks UT_Vector3 n = *pt->castAttribData<UT_Vector3>(detail->N_attrib); float r = *pt->castAttribData<float>(detail->R_attrib); n.normalize(); UT_Vector3 ref(1,0,0); UT_Vector3 up = ref; up.cross(n); up.normalize(); UT_Vector3 right = up; right.cross(n); right.normalize(); UT_DMatrix4 mat( right.x(), right.y(), right.z(), 0, up.x(), up.y(), up.z(), 0, n.x(), n.y(), n.z(), 0, pos.x(), pos.y(), pos.z(), 1 ); ren.pushMatrix(); ren.multiplyMatrix(mat); ren.pushColor( UT_Color( UT_RGB, col[0], col[1], col[2] ) ); ren.circlefW( 0, 0, detail->point_size * r, 8 ); ren.popColor(); ren.popMatrix(); } } } } if ( !detail->use_disk ) { ren.endPoint(); } } }