UT_Matrix3 RainData::computeRotationMatrix(UT_Vector3 rainDirection) { static const UT_Vector3 up(0.0, -1.0, 0.0); UT_Matrix3 rotDirMatrix(1.0); rainDirection.normalize(); UT_Vector3 axis = cross (up, rainDirection); axis.normalize(); fpreal angle = acos (dot (up, rainDirection)); rotDirMatrix.rotate (axis, -angle); // minus for proper generation // of the noise in // RainData::computeInitialPositions return rotDirMatrix; }
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_PrimGroupCentroid::baryCenter(const GU_Detail *input_geo, GA_Range &pr_range, const GA_PrimitiveList &prim_list, UT_Vector3 &pos) { GA_Range pt_range; GA_OffsetArray points; GA_OffsetArray::const_iterator points_it; // We need to iterate over each primitive in the range and // find out which points it references. for (GA_Iterator pr_it(pr_range); !pr_it.atEnd(); ++pr_it) { // Get the range of points for the primitive using the // offset from the primitive list. pt_range = prim_list.get(*pr_it)->getPointRange(); // Add each point's offset to the array, checking for duplicates. for (GA_Iterator pt_it(pt_range); !pt_it.atEnd(); ++pt_it) points.append(*pt_it, true); } // Reset the position. pos.assign(0,0,0); // Add the positions for all the points. for (points_it = points.begin(); !points_it.atEnd(); ++points_it) pos += input_geo->getPos3(*points_it); // Store the average position for all the points we found. pos /= points.entries(); }
void SOP_PrimGroupCentroid::centerOfMass(GA_Range &pr_range, const GA_PrimitiveList &prim_list, UT_Vector3 &pos) { fpreal area, total_area; const GEO_Primitive *prim; // Set the position and total area to 0. pos.assign(0,0,0); total_area = 0; // Iterate over all the primitives in the range. for (GA_Iterator it(pr_range); !it.atEnd(); ++it) { // Get the primitive. prim = (const GEO_Primitive *) prim_list.get(*it); // Calculate the area of the primitive. area = prim->calcArea(); // Add the barycenter multiplied by the area to the position. pos += prim->baryCenter() * area; // Add this primitive's area to the total area. total_area += area; } // If the total area is not 0, divide the position by the total area. if (total_area) pos /= total_area; }
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); } }
OP_ERROR SOP_Smoke_Source::cookMySop(OP_Context &context) { // We must lock our inputs before we try to access their geometry. // OP_AutoLockInputs will automatically unlock our inputs when we return. // NOTE: Don't call unlockInputs yourself when using this! OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); fpreal now = context.getTime(); duplicateSource(0, context); // These three lines enable the local variable support. This allows // $CR to get the red colour, for example, as well as supporting // any varmap created by the Attribute Create SOP. // Note that if you override evalVariableValue for your own // local variables (like SOP_Star does) it is essential you // still call the SOP_Node::evalVariableValue or you'll not // get any of the benefit of the built in local variables. // The variable order controls precedence for which attribute will be // be bound first if the same named variable shows up in multiple // places. This ordering ensures point attributes get precedence. setVariableOrder(3, 2, 0, 1); // The setCur* functions track which part of the gdp is currently // being processed - it is what is used in the evalVariableValue // callback as the current point. The 0 is for the first input, // you can have two inputs so $CR2 would get the second input's // value. setCurGdh(0, myGdpHandle); // Builds the lookup table matching attributes to the local variables. setupLocalVars(); // Here we determine which groups we have to work on. We only // handle point groups. if (error() < UT_ERROR_ABORT && cookInputGroups(context) < UT_ERROR_ABORT && (!myGroup || !myGroup->isEmpty())) { UT_AutoInterrupt progress("Flattening Points"); // Handle all position, normal, and vector attributes. // It's not entirely clear what to do for quaternion or transform attributes. // We bump the data IDs of the attributes to modify in advance, // since we're already looping over them, and we want to avoid // bumping them all for each point, in case that's slow. UT_Array<GA_RWHandleV3> positionattribs(1); UT_Array<GA_RWHandleV3> normalattribs; UT_Array<GA_RWHandleV3> vectorattribs; GA_Attribute *attrib; GA_FOR_ALL_POINT_ATTRIBUTES(gdp, attrib) { // Skip non-transforming attributes if (!attrib->needsTransform()) continue; GA_TypeInfo typeinfo = attrib->getTypeInfo(); if (typeinfo == GA_TYPE_POINT || typeinfo == GA_TYPE_HPOINT) { GA_RWHandleV3 handle(attrib); if (handle.isValid()) { positionattribs.append(handle); attrib->bumpDataId(); } } else if (typeinfo == GA_TYPE_NORMAL) { GA_RWHandleV3 handle(attrib); if (handle.isValid()) { normalattribs.append(handle); attrib->bumpDataId(); } } else if (typeinfo == GA_TYPE_VECTOR) { GA_RWHandleV3 handle(attrib); if (handle.isValid()) { vectorattribs.append(handle); attrib->bumpDataId(); } } } // Iterate over points up to GA_PAGE_SIZE at a time using blockAdvance. GA_Offset start; GA_Offset end; for (GA_Iterator it(gdp->getPointRange(myGroup)); it.blockAdvance(start, end);) { // Check if user requested abort if (progress.wasInterrupted()) break; for (GA_Offset ptoff = start; ptoff < end; ++ptoff) { // This sets the current point that is beint processed to // ptoff. This means that ptoff will be used for any // local variable for any parameter evaluation that occurs // after this point. // NOTE: Local variables and repeated parameter evaluation // is significantly slower and sometimes more complicated // than having a string parameter that specifies the name // of an attribute whose values should be used instead. // That parameter would only need to be evaluated once, // the attribute could be looked up once, and quickly // accessed; however, a separate point attribute would // be needed for each property that varies per point. // Local variable evaluation isn't threadsafe either, // whereas attributes can be read safely from multiple // threads. // // Long story short: *Local variables are terrible.* myCurPtOff[0] = ptoff; float dist = DIST(now); UT_Vector3 normal; if (!DIRPOP()) { switch (ORIENT()) { case 0 : // XY Plane normal.assign(0, 0, 1); break; case 1 : // YZ Plane normal.assign(1, 0, 0); break; case 2 : // XZ Plane normal.assign(0, 1, 0); break; } } else { normal.assign(NX(now), NY(now), NZ(now)); normal.normalize(); } // Project positions onto the plane by subtracting // off the normal component. for (exint i = 0; i < positionattribs.size(); ++i) { UT_Vector3 p = positionattribs(i).get(ptoff); p -= normal * (dot(normal, p) - dist); positionattribs(i).set(ptoff, p); } // Normals will now all either be normal or -normal. for (exint i = 0; i < normalattribs.size(); ++i) { UT_Vector3 n = normalattribs(i).get(ptoff); if (dot(normal, n) < 0) n = -normal; else n = normal; normalattribs(i).set(ptoff, n); } // Project vectors onto the plane through the origin by // subtracting off the normal component. for (exint i = 0; i < vectorattribs.size(); ++i) { UT_Vector3 v = vectorattribs(i).get(ptoff); v -= normal * dot(normal, v); vectorattribs(i).set(ptoff, v); } } } }
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 ParallelShift::operator()(const GA_SplittableRange &r) const { fpreal actualSpeed; fpreal parm1x,parm2x,parm1y,parm2y,parm1z,parm2z, parmInitial; UT_Vector3 p1x, p2x, p1y, p2y, p1z, p2z, p1, p2, initialPosition, p; fpreal pathLength, pathPeriod; fpreal integralPart; UT_Vector3 boundPoints[2]; UT_Vector3 vAttributeVector; GA_WOAttributeRef vAttributeRef = gdp_->addFloatTuple(GA_ATTRIB_POINT, "v", 3); const GA_AIFTuple* vAttribInterface = vAttributeRef.getAIFTuple(); for(GA_PageIterator pit = r.beginPages(); !pit.atEnd(); ++pit) { GA_Offset start, end; for (GA_Iterator it(pit.begin()); it.blockAdvance(start, end); ) { for (GA_Offset i = start; i < end; ++i) { actualSpeed = pRain_->getActualSpeed(i); vAttributeVector = pRain_->rainDirection_*actualSpeed; vAttribInterface->set( vAttributeRef.getAttribute(), i, vAttributeVector.data(), 3); initialPosition = pRain_->getInitialPosition(i); parm1x = (pRain_->maximumBounds_[0] - initialPosition[0]) / pRain_->rainDirection_[0]; parm2x = (pRain_->minimumBounds_[0] - initialPosition[0]) / pRain_->rainDirection_[0]; parm1y = (pRain_->maximumBounds_[1] - initialPosition[1]) / pRain_->rainDirection_[1]; parm2y = (pRain_->minimumBounds_[1] - initialPosition[1]) / pRain_->rainDirection_[1]; parm1z = (pRain_->maximumBounds_[2] - initialPosition[2]) / pRain_->rainDirection_[2]; parm2z = (pRain_->minimumBounds_[2] - initialPosition[2]) / pRain_->rainDirection_[2]; p1x = initialPosition + parm1x*pRain_->rainDirection_; p2x = initialPosition + parm2x*pRain_->rainDirection_; p1y = initialPosition + parm1y*pRain_->rainDirection_; p2y = initialPosition + parm2y*pRain_->rainDirection_; p1z = initialPosition + parm1z*pRain_->rainDirection_; p2z = initialPosition + parm2z*pRain_->rainDirection_; UT_Vector3 endsArray [6] = {p1x, p2x, p1y, p2y, p1z, p2z}; // ########### sort ######################################## UT_Vector3 tmpPoint; bool inBound; int endsFound = 0; int k = 0; while(k<6 && endsFound <2) { inBound = false; inBound = (endsArray[k][0] >= pRain_->minimumBounds_[0]) && (endsArray[k][1] >= pRain_->minimumBounds_[1]) && (endsArray[k][2] >= pRain_->minimumBounds_[2]) && (endsArray[k][0] <= pRain_->maximumBounds_[0]) && (endsArray[k][1] <= pRain_->maximumBounds_[1]) && (endsArray[k][2] <= pRain_->maximumBounds_[2]); if (inBound == true) { boundPoints[endsFound] = endsArray[k]; endsFound++; } k++; } if (boundPoints[0][1]<boundPoints[1][1]) { tmpPoint = boundPoints[1]; boundPoints[1] = boundPoints[0]; boundPoints[0] = tmpPoint; } // E#############end of sort ############################### pathLength = (boundPoints[0] - boundPoints[1]).length(); pathPeriod = pathLength / actualSpeed; parmInitial = (initialPosition - boundPoints[0]).length()/ pathLength; integralPart = parmInitial + pRain_->now_ / pathPeriod; p = boundPoints[0] + (integralPart - (int)integralPart) * (boundPoints[1] - boundPoints[0]); gdp_->setPos3(i, p); } } } }
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(); } } }