void liqRibData::parseVectorAttributes( MFnDependencyNode & nodeFn, MStringArray & strArray, ParameterType pType ) { int i; MStatus status; if ( strArray.length() > 0 ) { for ( i = 0; i < strArray.length(); i++ ) { liqTokenPointer tokenPointerPair; MString cutString = strArray[i].substring(5, strArray[i].length()); MPlug vPlug = nodeFn.findPlug( strArray[i] ); MObject plugObj; status = vPlug.getValue( plugObj ); if ( plugObj.apiType() == MFn::kVectorArrayData ) { MFnVectorArrayData fnVectorArrayData( plugObj ); MVectorArray vectorArrayData = fnVectorArrayData.array( &status ); tokenPointerPair.set( cutString.asChar(), pType, ( type() == MRT_Nurbs || type() == MRT_NuCurve ) ? true : false, true, false, vectorArrayData.length() ); for ( int kk = 0; kk < vectorArrayData.length(); kk++ ) { tokenPointerPair.setTokenFloat( kk, vectorArrayData[kk].x, vectorArrayData[kk].y, vectorArrayData[kk].z ); } // should it be per vertex or face-varying if ( ( ( type() == MRT_Mesh ) || ( type() == MRT_Subdivision ) ) && ( vectorArrayData.length() == faceVaryingCount ) ) { tokenPointerPair.setDetailType( rFaceVarying); } else { tokenPointerPair.setDetailType( rVertex ); } // store it all tokenPointerArray.push_back( tokenPointerPair ); } else { // Hmmmm float ? double ? float x, y, z; tokenPointerPair.set( cutString.asChar(), pType, ( type() == MRT_Nurbs || type() == MRT_NuCurve ) ? true : false, false, false, 0 ); vPlug.child(0).getValue( x ); vPlug.child(1).getValue( y ); vPlug.child(2).getValue( z ); tokenPointerPair.setTokenFloat( 0, x, y, z ); tokenPointerPair.setDetailType( rConstant ); tokenPointerArray.push_back( tokenPointerPair ); } } } }
void dynExprField::apply( MDataBlock &block, int receptorSize, const MDoubleArray &magnitudeArray, const MDoubleArray &magnitudeOwnerArray, const MVectorArray &directionArray, const MVectorArray &directionOwnerArray, MVectorArray &outputForce ) // // Compute output force for each particle. If there exists the // corresponding per particle attribute, use the data passed from // particle shape (stored in magnitudeArray and directionArray). // Otherwise, use the attribute value from the field. // { // get the default values MVector defaultDir = direction(block); double defaultMag = magnitude(block); int magArraySize = magnitudeArray.length(); int dirArraySize = directionArray.length(); int magOwnerArraySize = magnitudeOwnerArray.length(); int dirOwnerArraySize = directionOwnerArray.length(); int numOfOwner = magOwnerArraySize; if( dirOwnerArraySize > numOfOwner ) numOfOwner = dirOwnerArraySize; double magnitude = defaultMag; MVector direction = defaultDir; for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ ) { if(receptorSize == magArraySize) magnitude = magnitudeArray[ptIndex]; if(receptorSize == dirArraySize) direction = directionArray[ptIndex]; if( numOfOwner > 0) { for( int nthOwner = 0; nthOwner < numOfOwner; nthOwner++ ) { if(magOwnerArraySize == numOfOwner) magnitude = magnitudeOwnerArray[nthOwner]; if(dirOwnerArraySize == numOfOwner) direction = directionOwnerArray[nthOwner]; outputForce.append( direction * magnitude ); } } else { outputForce.append( direction * magnitude ); } } }
bool ProxyViz::loadInternal(MDataBlock& block) { MDataHandle tmH = block.inputValue(aplantTransformCache); MFnPointArrayData tmFn(tmH.data()); MPointArray plantTms = tmFn.array(); if(plantTms.length() < 1) return false; MDataHandle idH = block.inputValue(aplantIdCache); MFnIntArrayData idFn(idH.data()); MIntArray plantIds = idFn.array(); if(plantIds.length() < 1) return false; MDataHandle triH = block.inputValue(aplantTriangleIdCache); MFnIntArrayData triFn(triH.data()); MIntArray plantTris = triFn.array(); if(plantTris.length() < 1) return false; MDataHandle crdH = block.inputValue(aplantTriangleCoordCache); MFnVectorArrayData crdFn(crdH.data()); MVectorArray plantCoords = crdFn.array(); if(plantCoords.length() < 1) return false; MDataHandle cotH = block.inputValue(aplantOffsetCache); MFnVectorArrayData cotFn(cotH.data()); MVectorArray plantOffsets = cotFn.array(); return loadPlants(plantTms, plantIds, plantTris, plantCoords, plantOffsets); }
bool PxrUsdMayaWriteUtil::ReadMayaAttribute( const MFnDependencyNode& depNode, const MString& name, VtVec3fArray* val) { MStatus status; depNode.attribute(name, &status); if (status == MS::kSuccess) { MPlug plug = depNode.findPlug(name); MObject dataObj; if ( (plug.getValue(dataObj) == MS::kSuccess) && (dataObj.hasFn(MFn::kVectorArrayData)) ) { MFnVectorArrayData dData(dataObj, &status); if (status == MS::kSuccess) { MVectorArray arrayValues = dData.array(); size_t numValues = arrayValues.length(); val->resize(numValues); for (size_t i = 0; i < numValues; ++i) { (*val)[i].Set( arrayValues[i][0], arrayValues[i][1], arrayValues[i][2]); } return true; } } } return false; }
MStatus XmlCacheFormat::writeDoubleVectorArray( const MVectorArray& array ) { int size = array.length(); assert(size != 0); writeXmlTagValue(sizeTag,size); startXmlBlock( doubleVectorArrayTag ); for(int i = 0; i < size; i++) { writeXmlValue(array[i][0]); writeXmlValue(array[i][1]); writeXmlValue(array[i][2]); string endl("\n"); writeXmlValue(endl); } endXmlBlock(); return MS::kSuccess; }
MStatus dynExprField::compute(const MPlug& plug, MDataBlock& block) // // Descriptions: // compute output force. // { MStatus status; if( !(plug == mOutputForce) ) return( MS::kUnknownParameter ); // get the logical index of the element this plug refers to. // int multiIndex = plug.logicalIndex( &status ); McheckErr(status, "ERROR in plug.logicalIndex.\n"); // Get input data handle, use outputArrayValue since we do not // want to evaluate both inputs, only the one related to the // requested multiIndex. Evaluating both inputs at once would cause // a dependency graph loop. MArrayDataHandle hInputArray = block.outputArrayValue( mInputData, &status ); McheckErr(status,"ERROR in hInputArray = block.outputArrayValue().\n"); status = hInputArray.jumpToElement( multiIndex ); McheckErr(status, "ERROR: hInputArray.jumpToElement failed.\n"); // get children of aInputData. MDataHandle hCompond = hInputArray.inputValue( &status ); McheckErr(status, "ERROR in hCompond=hInputArray.inputValue\n"); MDataHandle hPosition = hCompond.child( mInputPositions ); MObject dPosition = hPosition.data(); MFnVectorArrayData fnPosition( dPosition ); MVectorArray points = fnPosition.array( &status ); McheckErr(status, "ERROR in fnPosition.array(), not find points.\n"); // Comment out the following since velocity, and mass are // not needed in this field. // // MDataHandle hVelocity = hCompond.child( mInputVelocities ); // MObject dVelocity = hVelocity.data(); // MFnVectorArrayData fnVelocity( dVelocity ); // MVectorArray velocities = fnVelocity.array( &status ); // McheckErr(status, "ERROR in fnVelocity.array(), not find velocities.\n"); // // MDataHandle hMass = hCompond.child( mInputMass ); // MObject dMass = hMass.data(); // MFnDoubleArrayData fnMass( dMass ); // MDoubleArray masses = fnMass.array( &status ); // McheckErr(status, "ERROR in fnMass.array(), not find masses.\n"); // The attribute mInputPPData contains the attribute in an array form // parpared by the particleShape if the particleShape has per particle // attribute fieldName_attrName. // // Suppose a field with the name dynExprField1 is connecting to // particleShape1, and the particleShape1 has per particle float attribute // dynExprField1_magnitude and vector attribute dynExprField1_direction, // then hInputPPArray will contains a MdoubleArray with the corresponding // name "magnitude" and a MvectorArray with the name "direction". This // is a mechanism to allow the field attributes being driven by dynamic // expression. MArrayDataHandle mhInputPPData = block.inputArrayValue( mInputPPData, &status ); McheckErr(status,"ERROR in mhInputPPData = block.inputArrayValue().\n"); status = mhInputPPData.jumpToElement( multiIndex ); McheckErr(status, "ERROR: mhInputPPArray.jumpToElement failed.\n"); MDataHandle hInputPPData = mhInputPPData.inputValue( &status ); McheckErr(status, "ERROR in hInputPPData = mhInputPPData.inputValue\n"); MObject dInputPPData = hInputPPData.data(); MFnArrayAttrsData inputPPArray( dInputPPData ); MDataHandle hOwnerPPData = block.inputValue( mOwnerPPData, &status ); McheckErr(status, "ERROR in hOwnerPPData = block.inputValue\n"); MObject dOwnerPPData = hOwnerPPData.data(); MFnArrayAttrsData ownerPPArray( dOwnerPPData ); const MString magString("magnitude"); MFnArrayAttrsData::Type doubleType(MFnArrayAttrsData::kDoubleArray); bool arrayExist; MDoubleArray magnitudeArray; arrayExist = inputPPArray.checkArrayExist(magString, doubleType, &status); // McheckErr(status, "ERROR in checkArrayExist(magnitude)\n"); if(arrayExist) { magnitudeArray = inputPPArray.getDoubleData(magString, &status); // McheckErr(status, "ERROR in inputPPArray.doubleArray(magnitude)\n"); } MDoubleArray magnitudeOwnerArray; arrayExist = ownerPPArray.checkArrayExist(magString, doubleType, &status); // McheckErr(status, "ERROR in checkArrayExist(magnitude)\n"); if(arrayExist) { magnitudeOwnerArray = ownerPPArray.getDoubleData(magString, &status); // McheckErr(status, "ERROR in ownerPPArray.doubleArray(magnitude)\n"); } const MString dirString("direction"); MFnArrayAttrsData::Type vectorType(MFnArrayAttrsData::kVectorArray); arrayExist = inputPPArray.checkArrayExist(dirString, vectorType, &status); MVectorArray directionArray; // McheckErr(status, "ERROR in checkArrayExist(direction)\n"); if(arrayExist) { directionArray = inputPPArray.getVectorData(dirString, &status); // McheckErr(status, "ERROR in inputPPArray.vectorArray(direction)\n"); } arrayExist = ownerPPArray.checkArrayExist(dirString, vectorType, &status); MVectorArray directionOwnerArray; // McheckErr(status, "ERROR in checkArrayExist(direction)\n"); if(arrayExist) { directionOwnerArray = ownerPPArray.getVectorData(dirString, &status); // McheckErr(status, "ERROR in ownerPPArray.vectorArray(direction)\n"); } // Compute the output force. // MVectorArray forceArray; apply( block, points.length(), magnitudeArray, magnitudeOwnerArray, directionArray, directionOwnerArray, forceArray ); // get output data handle // MArrayDataHandle hOutArray = block.outputArrayValue( mOutputForce, &status); McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n"); MArrayDataBuilder bOutArray = hOutArray.builder( &status ); McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n"); // get output force array from block. // MDataHandle hOut = bOutArray.addElement(multiIndex, &status); McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n"); MFnVectorArrayData fnOutputForce; MObject dOutputForce = fnOutputForce.create( forceArray, &status ); McheckErr(status, "ERROR in dOutputForce = fnOutputForce.create\n"); // update data block with new output force data. // hOut.set( dOutputForce ); block.setClean( plug ); return( MS::kSuccess ); }
MString CBPoseSpaceCmd::cacheResult(const MPointArray& bindPoints, const MPointArray& posePoints, const MVectorArray& dx, const MVectorArray& dy, const MVectorArray& dz) { MDGModifier modif; MObject opose = modif.createNode("sculptSpaceRecord"); modif.doIt(); unsigned count = dx.length(); MVectorArray row0Array; row0Array.setLength(count); MVectorArray row1Array; row1Array.setLength(count); MVectorArray row2Array; row2Array.setLength(count); MVectorArray row3Array; row3Array.setLength(count); MVectorArray bndArray; bndArray.setLength(count); MVectorArray posArray; posArray.setLength(count); float m[4][4]; for(unsigned i=0; i < count; i++) { m[0][0] = dx[i].x; m[0][1] = dx[i].y; m[0][2] = dx[i].z; m[0][3] = 0.f; m[1][0] = dy[i].x; m[1][1] = dy[i].y; m[1][2] = dy[i].z; m[1][3] = 0.f; m[2][0] = dz[i].x; m[2][1] = dz[i].y; m[2][2] = dz[i].z; m[2][3] = 0.f; m[3][0] = 0.f; m[3][1] = 0.f; m[3][2] = 0.f; m[3][3] = 1.f; MMatrix tm(m); tm = tm.inverse(); tm.get(m); row0Array[i].x = m[0][0]; row0Array[i].y = m[0][1]; row0Array[i].z = m[0][2]; row1Array[i].x = m[1][0]; row1Array[i].y = m[1][1]; row1Array[i].z = m[1][2]; row2Array[i].x = m[2][0]; row2Array[i].y = m[2][1]; row2Array[i].z = m[2][2]; row3Array[i].x = m[3][0]; row3Array[i].y = m[3][1]; row3Array[i].z = m[3][2]; bndArray[i] = bindPoints[i]; posArray[i] = posePoints[i]; } MFnDependencyNode fposec(opose); MStatus stat; MPlug pspacerow0 = fposec.findPlug("poseSpaceRow0", false, &stat); MPlug pspacerow1 = fposec.findPlug("poseSpaceRow1", false, &stat); MPlug pspacerow2 = fposec.findPlug("poseSpaceRow2", false, &stat); MPlug pspacerow3 = fposec.findPlug("poseSpaceRow3", false, &stat); MPlug pbind = fposec.findPlug("bpnt", false, &stat); MPlug ppose = fposec.findPlug("ppnt", false, &stat); MFnVectorArrayData frow0; MObject orow0 = frow0.create(row0Array); pspacerow0.setMObject(orow0); MFnVectorArrayData frow1; MObject orow1 = frow1.create(row1Array); pspacerow1.setMObject(orow1); MFnVectorArrayData frow2; MObject orow2 = frow2.create(row2Array); pspacerow2.setMObject(orow2); MFnVectorArrayData frow3; MObject orow3 = frow3.create(row3Array); pspacerow3.setMObject(orow3); MFnVectorArrayData fbind; MObject obind = fbind.create(bndArray); pbind.setMObject(obind); MFnVectorArrayData fpose; MObject oposed = fpose.create(posArray); ppose.setMObject(oposed); return fposec.name(); }
MString CBPoseSpaceCmd::saveResult(const MPointArray& bindPoints, const MPointArray& posePoints, const MVectorArray& dx, const MVectorArray& dy, const MVectorArray& dz) { unsigned count = dx.length(); float* data = new float[count * (3 + 3 + 16)]; for(unsigned i=0; i < count; i++) { data[i*3] = bindPoints[i].x; data[i*3+1] = bindPoints[i].y; data[i*3+2] = bindPoints[i].z; } unsigned offset = count * 3; for(unsigned i=0; i < count; i++) { data[offset+i*3] = posePoints[i].x; data[offset+i*3+1] = posePoints[i].y; data[offset+i*3+2] = posePoints[i].z; } offset = count * 6; for(unsigned i=0; i < count; i++) { float m[4][4]; m[0][0] = dx[i].x; m[0][1] = dx[i].y; m[0][2] = dx[i].z; m[0][3] = 0.f; m[1][0] = dy[i].x; m[1][1] = dy[i].y; m[1][2] = dy[i].z; m[1][3] = 0.f; m[2][0] = dz[i].x; m[2][1] = dz[i].y; m[2][2] = dz[i].z; m[2][3] = 0.f; m[3][0] = 0.f; m[3][1] = 0.f; m[3][2] = 0.f; m[3][3] = 1.f; MMatrix tm(m); tm = tm.inverse(); tm.get(m); unsigned ivx = offset+i*16; data[ivx] = m[0][0]; data[ivx+1] = m[0][1]; data[ivx+2] = m[0][2]; data[ivx+3] = m[0][3]; data[ivx+4] = m[1][0]; data[ivx+5] = m[1][1]; data[ivx+6] = m[1][2]; data[ivx+7] = m[1][3]; data[ivx+8] = m[2][0]; data[ivx+9] = m[2][1]; data[ivx+10] = m[2][2]; data[ivx+11] = m[2][3]; data[ivx+12] = m[3][0]; data[ivx+13] = m[3][1]; data[ivx+14] = m[3][2]; data[ivx+15] = m[3][3]; } io::filtering_ostream out; out.push(boost::iostreams::gzip_compressor()); MString filename = _cacheName; if(filename == "") { MString projRoot; MGlobal::executeCommand(MString("workspace -q -dir"), projRoot, 0, 0); projRoot = projRoot + "/poses/"; if(!exists( projRoot.asChar() )) { create_directory(projRoot.asChar()); } const ptime now = second_clock::local_time(); std::string file_time = to_iso_string(now); filename = projRoot+file_time.c_str()+".pos"; } out.push(io::file_sink(filename.asChar(), ios::binary)); out.write((char*)data, count*(3 + 3 + 16)*4); out.flush(); delete[] data; MGlobal::displayInfo(MString("corrective blendshape writes pose cache to ") + filename); return filename; }
void simpleFluidEmitter::omniFluidEmitter( MFnFluid& fluid, const MMatrix& fluidWorldMatrix, int plugIndex, MDataBlock& block, double dt, double conversion, double dropoff ) //============================================================================== // // Method: // // simpleFluidEmitter::omniFluidEmitter // // Description: // // Emits fluid from a point, or from a set of object control points. // // Parameters: // // fluid: fluid into which we are emitting // fluidWorldMatrix: object->world matrix for the fluid // plugIndex: identifies which fluid connected to the emitter // we are emitting into // block: datablock for the emitter, to retrieve attribute // values // dt: time delta for this frame // conversion: mapping from UI emission rates to internal units // dropoff: specifies how much emission rate drops off as // we move away from each emission point. // // Notes: // // If no owner object is present for the emitter, we simply emit from // the emitter position. If an owner object is present, then we emit // from each control point of that object in an identical fashion. // // To associate an owner object with an emitter, use the // addDynamic MEL command, e.g. "addDynamic simpleFluidEmitter1 pPlane1". // //============================================================================== { // find the positions that we need to emit from // MVectorArray emitterPositions; // first, try to get them from an owner object, which will have its // "ownerPositionData" attribute feeding into the emitter. These // values are in worldspace // bool gotOwnerPositions = false; MObject ownerShape = getOwnerShape(); if( ownerShape != MObject::kNullObj ) { MStatus status; MDataHandle hOwnerPos = block.inputValue( mOwnerPosData, &status ); if( status == MS::kSuccess ) { MObject dOwnerPos = hOwnerPos.data(); MFnVectorArrayData fnOwnerPos( dOwnerPos ); MVectorArray posArray = fnOwnerPos.array( &status ); if( status == MS::kSuccess ) { // assign vectors from block to ownerPosArray. // for( unsigned int i = 0; i < posArray.length(); i ++ ) { emitterPositions.append( posArray[i] ); } gotOwnerPositions = true; } } } // there was no owner object, so we just use the emitter position for // emission. // if( !gotOwnerPositions ) { MPoint emitterPos = getWorldPosition(); emitterPositions.append( emitterPos ); } // get emission rates for density, fuel, heat, and emission color // double densityEmit = fluidDensityEmission( block ); double fuelEmit = fluidFuelEmission( block ); double heatEmit = fluidHeatEmission( block ); bool doEmitColor = fluidEmitColor( block ); MColor emitColor = fluidColor( block ); // rate modulation based on frame time, user value conversion factor, and // standard emitter "rate" value (not actually exposed in most fluid // emitters, but there anyway). // double theRate = getRate(block) * dt * conversion; // get voxel dimensions and sizes (object space) // double size[3]; unsigned int res[3]; fluid.getDimensions( size[0], size[1], size[2] ); fluid.getResolution( res[0], res[1], res[2] ); // voxel sizes double dx = size[0] / res[0]; double dy = size[1] / res[1]; double dz = size[2] / res[2]; // voxel centers double Ox = -size[0]/2; double Oy = -size[1]/2; double Oz = -size[2]/2; // emission will only happen for voxels whose centers lie within // "minDist" and "maxDist" of an emitter position // double minDist = getMinDistance( block ); double maxDist = getMaxDistance( block ); // bump up the min/max distance values so that they // are both > 0, and there is at least about a half // voxel between the min and max values, to prevent aliasing // artifacts caused by emitters missing most voxel centers // MTransformationMatrix fluidXform( fluidWorldMatrix ); double fluidScale[3]; fluidXform.getScale( fluidScale, MSpace::kWorld ); // compute smallest voxel diagonal length double wsX = fabs(fluidScale[0]*dx); double wsY = fabs(fluidScale[1]*dy); double wsZ = fabs(fluidScale[2]*dz); double wsMin = MIN( MIN( wsX, wsY), wsZ ); double wsMax = MAX( MAX( wsX, wsY), wsZ ); double wsDiag = wsMin * sqrt(3.0); // make sure emission range is bigger than 0.5 voxels if ( maxDist <= minDist || maxDist <= (wsDiag/2.0) ) { if ( minDist < 0 ) minDist = 0; maxDist = minDist + wsDiag/2.0; dropoff = 0; } // Now, it's time to actually emit into the fluid: // // foreach emitter point // foreach voxel // - select some points in the voxel // - compute a dropoff function from the emitter point // - emit an appropriate amount of fluid into the voxel // // Since we've already expanded the min/max distances to cover // the smallest voxel dimension, we should only need 1 sample per // voxel, unless the voxels are highly non-square. We increase the // number of samples in these cases. // // If the "jitter" flag is enabled, we jitter each sample position, // using the rangen() function, which keeps track of independent // random states for each fluid, to make sure that results are // repeatable for multiple simulation runs. // // basic sample count int numSamples = 1; // increase samples if necessary for non-square voxels if(wsMin >.00001) { numSamples = (int)(wsMax/wsMin + .5); if(numSamples > 8) numSamples = 8; if(numSamples < 1) numSamples = 1; } bool jitter = fluidJitter(block); if( !jitter ) { // I don't have a good uniform sample generator for an // arbitrary number of samples. It would be a good idea to use // one here. For now, just use 1 sample for the non-jittered case. // numSamples = 1; } for( unsigned int p = 0; p < emitterPositions.length(); p++ ) { MPoint emitterWorldPos = emitterPositions[p]; // loop through all voxels, looking for ones that lie at least // partially within the dropoff field around this emitter point // for( unsigned int i = 0; i < res[0]; i++ ) { double x = Ox + i*dx; for( unsigned int j = 0; j < res[1]; j++ ) { double y = Oy + j*dy; for( unsigned int k = 0; k < res[2]; k++ ) { double z = Oz + k*dz; int si; for( si = 0; si < numSamples; si++ ) { // compute sample point (fluid object space) // double rx, ry, rz; if( jitter ) { rx = x + randgen()*dx; ry = y + randgen()*dy; rz = z + randgen()*dz; } else { rx = x + 0.5*dx; ry = y + 0.5*dy; rz = z + 0.5*dz; } // compute distance from sample to emitter point // MPoint point( rx, ry, rz ); point *= fluidWorldMatrix; MVector diff = point - emitterWorldPos; double distSquared = diff * diff; double dist = diff.length(); // discard if outside min/max range // if( (dist < minDist) || (dist > maxDist) ) { continue; } // drop off the emission rate according to the falloff // parameter, and divide to accound for multiple samples // in the voxel // double distDrop = dropoff * distSquared; double newVal = theRate * exp( -distDrop ) / (double)numSamples; // emit density/heat/fuel/color into the current voxel // if( newVal != 0 ) { fluid.emitIntoArrays( (float) newVal, i, j, k, (float)densityEmit, (float)heatEmit, (float)fuelEmit, doEmitColor, emitColor ); } float *fArray = fluid.falloff(); if( fArray != NULL ) { MPoint midPoint( x+0.5*dx, y+0.5*dy, z+0.5*dz ); midPoint.x *= 0.2; midPoint.y *= 0.2; midPoint.z *= 0.2; float fdist = (float) sqrt( midPoint.x*midPoint.x + midPoint.y*midPoint.y + midPoint.z*midPoint.z ); fdist /= sqrtf(3.0f); fArray[fluid.index(i,j,k)] = 1.0f-fdist; } } } } } } }
void sweptEmitter::emit ( const MVectorArray &inPosAry, // points where new particles from const MVectorArray &inVelAry, // initial velocity of new particles const MIntArray &emitCountPP, // # of new particles per point double dt, // elapsed time double speed, // speed factor double inheritFactor, // for inherit velocity MVector dirV, // emit direction MVectorArray &outPosAry, // holding new particles position MVectorArray &outVelAry // holding new particles velocity ) // // Descriptions: // { // check the length of input arrays. // int posLength = inPosAry.length(); int velLength = inVelAry.length(); int countLength = emitCountPP.length(); if( (posLength != velLength) || (posLength != countLength) ) return; // Compute total emit count. // int index; int totalCount = 0; for( index = 0; index < countLength; index ++ ) totalCount += emitCountPP[index]; if( totalCount <= 0 ) return; // Map direction vector into world space and normalize it. // dirV.normalize(); // Start emission. // int emitCount; MVector newPos, newVel; MVector prePos, sPos, sVel; for( index = 0; index < posLength; index++ ) { emitCount = emitCountPP[index]; if( emitCount <= 0 ) continue; sPos = inPosAry[index]; sVel = inVelAry[index]; prePos = sPos - sVel * dt; for( int i = 0; i < emitCount; i++ ) { double alpha = ( (double)i + drand48() ) / (double)emitCount; newPos = (1 - alpha) * prePos + alpha * sPos; newVel = dirV * speed; newPos += newVel * ( dt * (1 - alpha) ); newVel += sVel * inheritFactor; // Add new data into output arrays. // outPosAry.append( newPos ); outVelAry.append( newVel ); } } }
MStatus ProxyViz::compute( const MPlug& plug, MDataBlock& block ) { if(!m_enableCompute) return MS::kSuccess; if( plug == outValue ) { updateWorldSpace(thisMObject() ); MStatus status; ExampVox * defBox = plantExample(0); defBox->setGeomSizeMult(block.inputValue(aradiusMult).asFloat() ); defBox->setGeomBox(block.inputValue(abboxminx).asFloat(), block.inputValue(abboxminy).asFloat(), block.inputValue(abboxminz).asFloat(), block.inputValue(abboxmaxx).asFloat(), block.inputValue(abboxmaxy).asFloat(), block.inputValue(abboxmaxz).asFloat()); float grdsz = defBox->geomExtent() * 32.f ; if(grdsz < 32.f) { AHelper::Info<float>(" ProxyViz input box is too small", grdsz); grdsz = 32.f; AHelper::Info<float>(" trancated to", grdsz); } if(m_toSetGrid) { m_toSetGrid = false; resetGrid(grdsz); } if(_firstLoad) { /// internal cache only, initializing from external cache is obsolete if(!loadInternal(block) ) std::cout<<"\n ERROR proxviz cannot load internal cache"; _firstLoad = 0; } if(!m_toCheckVisibility) { MArrayDataHandle groundMeshArray = block.inputArrayValue(agroundMesh ); MArrayDataHandle groundSpaceArray = block.inputArrayValue(agroundSpace ); /// in case no ground is connected if(updateGround(groundMeshArray, groundSpaceArray )) { moveWithGround(); AHelper::Info<std::string>(" ProxyViz ground ", groundBuildLog() ); } } if(!m_hasParticle) { block.setClean(plug); return MS::kSuccess; } const int ngroups = block.inputValue(agroupcount).asInt(); MDataHandle hdata = block.inputValue(outPositionPP, &status); MFnVectorArrayData farray(hdata.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system"); block.setClean(plug); return MS::kSuccess; } MDataHandle scaledata = block.inputValue(outScalePP, &status); MFnVectorArrayData scalearray(scaledata.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system"); block.setClean(plug); return MS::kSuccess; } MDataHandle rotatedata = block.inputValue(outRotationPP, &status); MFnVectorArrayData rotatearray(rotatedata.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system"); block.setClean(plug); return MS::kSuccess; } MDataHandle replaceData = block.inputValue(outReplacePP, &status); MFnDoubleArrayData replaceArrayFn(replaceData.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system, needs userScalarPP"); block.setClean(plug); return MS::kSuccess; } MVectorArray outPosArray = farray.array(); MVectorArray outScaleArray = scalearray.array(); MVectorArray outRotateArray = rotatearray.array(); MDoubleArray outReplaceArray = replaceArrayFn.array(); if( outPosArray.length() < 1) { block.setClean(plug); return MS::kSuccess; } computePPAttribs(outPosArray, outRotateArray, outScaleArray, outReplaceArray, ngroups); float result = outPosArray.length(); MDataHandle outputHandle = block.outputValue( outValue ); outputHandle.set( result ); block.setClean(plug); } if(plug == outValue1) { MArrayDataHandle hArray = block.inputArrayValue(ainexamp); updateExamples(hArray); float result = 91.f; MDataHandle outputHandle = block.outputValue( outValue1 ); outputHandle.set( result ); block.setClean(plug); } return MS::kSuccess; }
// // Main routine /////////////////////////////////////////////////////////////////////////////// MStatus particleSystemInfoCmd::doIt( const MArgList& args ) { MStatus stat = parseArgs( args ); if( stat != MS::kSuccess ) return stat; if( particleNode.isNull() ) { MObject parent; MFnParticleSystem dummy; particleNode = dummy.create(&stat); CHECKRESULT(stat,"MFnParticleSystem::create(status) failed!"); MFnParticleSystem ps( particleNode, &stat ); CHECKRESULT(stat,"MFnParticleSystem::MFnParticleSystem(MObject,status) failed!"); MPointArray posArray; posArray.append(MPoint(-5, 5, 0)); posArray.append(MPoint(-5, 10, 0)); MVectorArray velArray; velArray.append(MPoint(1, 1, 0)); velArray.append(MPoint(1, 1, 0)); stat = ps.emit(posArray, velArray); CHECKRESULT(stat,"MFnParticleSystem::emit(posArray,velArray) failed!"); stat = ps.emit(MPoint(5, 5, 0)); CHECKRESULT(stat,"MFnParticleSystem::emit(pos) failed!"); stat = ps.emit(MPoint(5, 10, 0)); CHECKRESULT(stat,"MFnParticleSystem::emit(pos) failed!"); stat = ps.saveInitialState(); CHECKRESULT(stat,"MFnParticleSystem::saveInitialState() failed!"); MVectorArray accArray; accArray.setLength(4); for( unsigned int i=0; i<accArray.length(); i++ ) { MVector& acc = accArray[i]; acc.x = acc.y = acc.z = 3.0; } MString accName("acceleration"); ps.setPerParticleAttribute( accName, accArray, &stat ); CHECKRESULT(stat,"MFnParticleSystem::setPerParticleAttribute(vectorArray) failed!"); } MFnParticleSystem ps( particleNode, &stat ); CHECKRESULT(stat,"MFnParticleSystem::MFnParticleSystem(MObject,status) failed!"); if( ! ps.isValid() ) { MGlobal::displayError( "The function set is invalid!" ); return MS::kFailure; } const MString name = ps.particleName(); const MFnParticleSystem::RenderType psType = ps.renderType(); const unsigned int count = ps.count(); const char* typeString = NULL; switch( psType ) { case MFnParticleSystem::kCloud: typeString = "Cloud"; break; case MFnParticleSystem::kTube: typeString = "Tube system"; break; case MFnParticleSystem::kBlobby: typeString = "Blobby"; break; case MFnParticleSystem::kMultiPoint: typeString = "MultiPoint"; break; case MFnParticleSystem::kMultiStreak: typeString = "MultiStreak"; break; case MFnParticleSystem::kNumeric: typeString = "Numeric"; break; case MFnParticleSystem::kPoints: typeString = "Points"; break; case MFnParticleSystem::kSpheres: typeString = "Spheres"; break; case MFnParticleSystem::kSprites: typeString = "Sprites"; break; case MFnParticleSystem::kStreak: typeString = "Streak"; break; default: typeString = "Particle system"; assert( false ); break; } char buffer[256]; sprintf( buffer, "%s \"%s\" has %u primitives.", typeString, name.asChar(), count ); MGlobal::displayInfo( buffer ); unsigned i; MIntArray ids; ps.particleIds( ids ); sprintf( buffer, "count : %u ", count ); MGlobal::displayInfo( buffer ); sprintf( buffer, "%u ids.", ids.length() ); MGlobal::displayInfo( buffer ); assert( ids.length() == count ); for( i=0; i<ids.length(); i++ ) { sprintf( buffer, "id %d ", ids[i] ); MGlobal::displayInfo( buffer ); } MVectorArray positions; ps.position( positions ); assert( positions.length() == count ); for( i=0; i<positions.length(); i++ ) { MVector& p = positions[i]; sprintf( buffer, "pos %f %f %f ", p[0], p[1], p[2] ); MGlobal::displayInfo( buffer ); } MVectorArray vels; ps.velocity( vels ); assert( vels.length() == count ); for( i=0; i<vels.length(); i++ ) { const MVector& v = vels[i]; sprintf( buffer, "vel %f %f %f ", v[0], v[1], v[2] ); MGlobal::displayInfo( buffer ); } MVectorArray accs; ps.acceleration( accs ); assert( accs.length() == count ); for( i=0; i<accs.length(); i++ ) { const MVector& a = accs[i]; sprintf( buffer, "acc %f %f %f ", a[0], a[1], a[2] ); MGlobal::displayInfo( buffer ); } bool flag = ps.isDeformedParticleShape(&stat); CHECKRESULT(stat,"MFnParticleSystem::isDeformedParticleShape() failed!"); if( flag ) { MObject obj = ps.originalParticleShape(&stat); CHECKRESULT(stat,"MFnParticleSystem::originalParticleShape() failed!"); if( obj != MObject::kNullObj ) { MFnParticleSystem ps( obj ); sprintf( buffer, "original particle shape : %s ", ps.particleName().asChar() ); MGlobal::displayInfo( buffer ); } } flag = ps.isDeformedParticleShape(&stat); CHECKRESULT(stat,"MFnParticleSystem::isDeformedParticleShape() failed!"); if( !flag ) { MObject obj = ps.deformedParticleShape(&stat); CHECKRESULT(stat,"MFnParticleSystem::deformedParticleShape() failed!"); if( obj != MObject::kNullObj ) { MFnParticleSystem ps( obj ); sprintf( buffer, "deformed particle shape : %s ", ps.particleName().asChar() ); MGlobal::displayInfo( buffer ); } } if( ids.length() == positions.length() && ids.length() == vels.length() && ids.length() == accs.length() ) { setResult( int(ids.length()) ); } else { setResult( int(-1) ); } return MS::kSuccess; }
void apiSimpleShapeUI::drawVertices( const MDrawRequest & request, M3dView & view ) const // // Description: // // Component (vertex) drawing routine // // Arguments: // // request - request to be drawn // view - view to draw into // { MDrawData data = request.drawData(); MVectorArray * geom = (MVectorArray*)data.geometry(); view.beginGL(); // Query current state so it can be restored // bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false; if ( lightingWasOn ) { glDisable( GL_LIGHTING ); } float lastPointSize; glGetFloatv( GL_POINT_SIZE, &lastPointSize ); // Set the point size of the vertices // glPointSize( POINT_SIZE ); // If there is a component specified by the draw request // then loop over comp (using an MFnComponent class) and draw the // active vertices, otherwise draw all vertices. // MObject comp = request.component(); if ( ! comp.isNull() ) { MFnSingleIndexedComponent fnComponent( comp ); for ( int i=0; i<fnComponent.elementCount(); i++ ) { int index = fnComponent.element( i ); glBegin( GL_POINTS ); MVector& point = (*geom)[index]; glVertex3f( (float)point[0], (float)point[1], (float)point[2] ); glEnd(); char annotation[32]; sprintf( annotation, "%d", index ); view.drawText( annotation, point ); } } else { for ( unsigned int i=0; i<geom->length(); i++ ) { glBegin( GL_POINTS ); MVector point = (*geom)[ i ]; glVertex3f( (float)point[0], (float)point[1], (float)point[2] ); glEnd(); } } // Restore the state // if ( lightingWasOn ) { glEnable( GL_LIGHTING ); } glPointSize( lastPointSize ); view.endGL(); }
MStatus particlePathsCmd::doIt( const MArgList& args ) { MStatus stat = parseArgs( args ); if( stat != MS::kSuccess ) { return stat; } MFnParticleSystem cloud( particleNode ); if( ! cloud.isValid() ) { MGlobal::displayError( "The function set is invalid!" ); return MS::kFailure; } // // Create curves from the particle system in two stages. First, sample // all particle positions from the start time to the end time. Then, // use the data that was collected to create curves. // // Create the particle hash table at a fixed size. This should work fine // for small particle systems, but may become inefficient for larger ones. // If the plugin is running very slow, increase the size. The value should // be roughly the number of particles that are expected to be emitted // within the time period. // ParticleIdHash hash(1024); MIntArray idList; // // Stage 1 // MVectorArray positions; MIntArray ids; int i = 0; for (double time = start; time <= finish + TOLERANCE; time += increment) { MTime timeSeconds(time,MTime::kSeconds); // It is necessary to query the worldPosition attribute to force the // particle positions to update. // cloud.evaluateDynamics(timeSeconds,false); // MGlobal::executeCommand(MString("getAttr ") + cloud.name() + // MString(".worldPosition")); if (!cloud.isValid()) { MGlobal::displayError( "Particle system has become invalid." ); return MS::kFailure; } MGlobal::displayInfo( MString("Received ") + (int)(cloud.count()) + " particles, at time " + time); // Request position and ID data for particles // cloud.position( positions ); cloud.particleIds( ids ); if (ids.length() != cloud.count() || positions.length() != cloud.count()) { MGlobal::displayError( "Invalid array sizes." ); return MS::kFailure; } for (int j = 0; j < (int)cloud.count(); j++) { // Uncomment to show particle positions as the plugin accumulates // samples. /* MGlobal::displayInfo(MString("(") + (positions[j])[0] + MString(",") + (positions[j])[1] + MString(",") + (positions[j])[2] + MString(")")); */ MPoint pt(positions[j]); if (hash.getPoints(ids[j]).length() == 0) { idList.append(ids[j]); } hash.insert(ids[j],pt); } i++; } // // Stage 2 // for (i = 0; i < (int)(idList.length()); i++) { MPointArray points = hash.getPoints(idList[i]); // Don't bother with single samples if (points.length() <= 1) { continue; } // Add two additional points, so that the curve covers all sampled // values. // MPoint p1 = points[0]*2 - points[1]; MPoint p2 = points[points.length()-1]*2 - points[points.length()-2]; points.insert(p1,0); points.append(p2); // Uncomment to show information about the generated curves /* MGlobal::displayInfo( MString("ID ") + (int)(idList[i]) + " has " + (int)(points.length()) + " curve points."); for (int j = 0; j < (int)(points.length()); j++) { MGlobal::displayInfo(MString("(") + points[j][0] + MString(",") + points[j][1] + MString(",") + points[j][2] + MString(")")); } */ MDoubleArray knots; knots.insert(0.0,0); for (int j = 0; j < (int)(points.length()); j++) { knots.append((double)j); } knots.append(points.length()-1); MStatus status; MObject dummy; MFnNurbsCurve curve; curve.create(points,knots,3,MFnNurbsCurve::kOpen,false,false,dummy,&status); if (!status) { MGlobal::displayError("Failed to create nurbs curve."); return MS::kFailure; } } return MS::kSuccess; }
bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECore::MeshPrimitive>( from ); assert( mesh ); if ( !mesh->arePrimitiveVariablesValid() ) { return false; } MFloatPointArray vertexArray; MIntArray polygonCounts; MIntArray polygonConnects; MFnMesh fnMesh; int numVertices = 0; IECore::PrimitiveVariableMap::const_iterator it = mesh->variables.find("P"); if ( it != mesh->variables.end() ) { /// \todo Employ some M*Array converters to simplify this IECore::ConstV3fVectorDataPtr p = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data); if (p) { numVertices = p->readable().size(); vertexArray.setLength( numVertices ); for (int i = 0; i < numVertices; i++) { vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3f>( p->readable()[i] ); } } else { IECore::ConstV3dVectorDataPtr p = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data); if (p) { numVertices = p->readable().size(); vertexArray.setLength( numVertices ); for (int i = 0; i < numVertices; i++) { vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3d>( p->readable()[i] ); } } else { // "P" is not convertible to an array of "points" return false; } } } IECore::ConstIntVectorDataPtr verticesPerFace = mesh->verticesPerFace(); assert( verticesPerFace ); int numPolygons = verticesPerFace->readable().size(); polygonCounts.setLength( numPolygons ); for (int i = 0; i < numPolygons; i++) { polygonCounts[i] = verticesPerFace->readable()[i]; } IECore::ConstIntVectorDataPtr vertexIds = mesh->vertexIds(); assert( vertexIds ); int numPolygonConnects = vertexIds->readable().size(); polygonConnects.setLength( numPolygonConnects ); for (int i = 0; i < numPolygonConnects; i++) { polygonConnects[i] = vertexIds->readable()[i]; } MObject mObj = fnMesh.create( numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, to, &s ); if (!s) { return false; } it = mesh->variables.find("N"); if ( it != mesh->variables.end() ) { if (it->second.interpolation == IECore::PrimitiveVariable::FaceVarying ) { /// \todo Employ some M*Array converters to simplify this MVectorArray vertexNormalsArray; IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data); if (n) { int numVertexNormals = n->readable().size(); vertexNormalsArray.setLength( numVertexNormals ); for (int i = 0; i < numVertexNormals; i++) { vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3f>( n->readable()[i] ); } } else { IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data); if (n) { int numVertexNormals = n->readable().size(); vertexNormalsArray.setLength( numVertexNormals ); for (int i = 0; i < numVertexNormals; i++) { vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3d>( n->readable()[i] ); } } else { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"N\" has unsupported type \"%s\"." ) % it->second.data->typeName() ); } } if ( vertexNormalsArray.length() ) { MStatus status; MItMeshPolygon itPolygon( mObj, &status ); if( status != MS::kSuccess ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to create mesh iterator" ); } unsigned v = 0; MIntArray vertexIds; MIntArray faceIds; for ( ; !itPolygon.isDone(); itPolygon.next() ) { for ( v=0; v < itPolygon.polygonVertexCount(); ++v ) { faceIds.append( itPolygon.index() ); vertexIds.append( itPolygon.vertexIndex( v ) ); } } if( !fnMesh.setFaceVertexNormals( vertexNormalsArray, faceIds, vertexIds ) ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Setting normals failed" ); } } } else { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "PrimitiveVariable \"N\" has unsupported interpolation (expected FaceVarying)." ); } } bool haveDefaultUVs = false; IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( "s" ); IECore::RefCountedPtr sDataRef = ( sIt == mesh->variables.end() ) ? 0 : static_cast<IECore::RefCountedPtr>( sIt->second.data ); /// Add named UV sets std::set< std::string > uvSets; for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { const std::string &sName = it->first; size_t suffixOffset = sName.rfind( "_s" ); if ( ( suffixOffset != std::string::npos) && ( suffixOffset == sName.length() - 2 ) ) { std::string uvSetNameStr = sName.substr( 0, suffixOffset ); if ( uvSetNameStr.size() ) { MString uvSetName = uvSetNameStr.c_str(); std::string tName = uvSetNameStr + "_t"; std::string stIdName = uvSetNameStr + "Indices"; addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName ); uvSets.insert( uvSetNameStr ); if ( sDataRef == static_cast<IECore::RefCountedPtr>( it->second.data ) ) { haveDefaultUVs = true; } } } } /// Add default UV set if it isn't just a reference to a named set if ( !haveDefaultUVs ) { addUVSet( fnMesh, polygonCounts, mesh, "s", "t", "stIndices" ); } // We do the search again, but looking for primvars ending "_t", so we can catch cases where either "UVSETNAME_s" or "UVSETNAME_t" is present, but not both, taking care // not to attempt adding any duplicate sets for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { const std::string &tName = it->first; size_t suffixOffset = tName.rfind( "_t" ); if ( ( suffixOffset != std::string::npos) && ( suffixOffset == tName.length() - 2 ) ) { std::string uvSetNameStr = tName.substr( 0, suffixOffset ); if ( uvSetNameStr.size() && uvSets.find( uvSetNameStr ) == uvSets.end() ) { MString uvSetName = uvSetNameStr.c_str(); std::string sName = uvSetNameStr + "_s"; std::string stIdName = uvSetNameStr + "Indices"; addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName ); uvSets.insert( uvSetNameStr ); } } } /// If we're making a mesh node (rather than a mesh data) then make sure it belongs /// to the default shading group and add the ieMeshInterpolation attribute. MObject oMesh = fnMesh.object(); if( oMesh.apiType()==MFn::kMesh ) { assignDefaultShadingGroup( oMesh ); setMeshInterpolationAttribute( oMesh, mesh->interpolation() ); } /// \todo Other primvars, e.g. vertex color ("Cs") return true; }
MStatus PTCMapCmd::doIt( const MArgList& args) { MStatus status = parseArgs( args ); if( status != MS::kSuccess ) return status; MArgDatabase argData(syntax(), args); MAnimControl timeControl; MTime time = timeControl.currentTime(); int frame =int(time.value()); MString proj; MGlobal::executeCommand( MString ("string $p = `workspace -q -fn`"), proj ); MString cache_path = proj + "/data"; MString cache_name = "foo"; MString cache_attrib; double cache_mindist = 0.1; int max_level = 3; double root_size = 32; MString dem_trans = "nil"; double cloud_os = 0.05; MString key_trans = "nil"; MString eye_trans = "nil"; if (argData.isFlagSet("-p")) argData.getFlagArgument("-p", 0, cache_path); if (argData.isFlagSet("-n")) argData.getFlagArgument("-n", 0, cache_name); if (argData.isFlagSet("-a")) argData.getFlagArgument("-a", 0, cache_attrib); if (argData.isFlagSet("-mnd")) argData.getFlagArgument("-mnd", 0, cache_mindist); if (argData.isFlagSet("-ml")) argData.getFlagArgument("-ml", 0, max_level); if (argData.isFlagSet("-rs")) argData.getFlagArgument("-rs", 0, root_size); if (argData.isFlagSet("-t")) argData.getFlagArgument("-t", 0, dem_trans); if(argData.isFlagSet("-o")) argData.getFlagArgument("-o", 0, cloud_os); if(argData.isFlagSet("-tk")) argData.getFlagArgument("-tk", 0, key_trans); if(argData.isFlagSet("-te")) argData.getFlagArgument("-te", 0, eye_trans); float def_area = root_size; int last = 0; while(last < max_level-2) { def_area /= 2; last++; } def_area = 1.0f; //def_area *= def_area; // get bounding box center MDagPath p_bbox; zWorks::getTypedPathByName(MFn::kTransform, dem_trans, p_bbox); MObject o_bbox = p_bbox.transform(); float m_space[4][4]; m_space[0][0]=1; m_space[0][1]=0; m_space[0][2]=0; m_space[1][0]=0; m_space[1][1]=1; m_space[1][2]=0; m_space[2][0]=0; m_space[2][1]=0; m_space[2][2]=1; m_space[3][0]=0; m_space[3][1]=0; m_space[3][2]=0; if(o_bbox.isNull()) MGlobal::displayWarning("Cannot find pmap dimension, use default space."); else zWorks::getTransformWorldNoScale(p_bbox.partialPathName(), m_space); XYZ root_center(m_space[3][0], m_space[3][1], m_space[3][2]); // get key light dir MDagPath p_key; zWorks::getTypedPathByName(MFn::kTransform, key_trans, p_key); MObject o_key = p_key.transform(); m_space[0][0]=1; m_space[0][1]=0; m_space[0][2]=0; m_space[1][0]=0; m_space[1][1]=1; m_space[1][2]=0; m_space[2][0]=0; m_space[2][1]=0; m_space[2][2]=1; m_space[3][0]=0; m_space[3][1]=0; m_space[3][2]=0; if(o_key.isNull()) MGlobal::displayWarning("Cannot find key camera, use default space."); else zWorks::getTransformWorldNoScale(p_key.partialPathName(), m_space); XYZ key_dir(m_space[2][0], m_space[2][1], m_space[2][2]); key_dir.normalize(); // get view dir MDagPath p_eye; zWorks::getTypedPathByName(MFn::kTransform, eye_trans, p_eye); MObject o_eye = p_eye.transform(); m_space[0][0]=1; m_space[0][1]=0; m_space[0][2]=0; m_space[1][0]=0; m_space[1][1]=1; m_space[1][2]=0; m_space[2][0]=0; m_space[2][1]=0; m_space[2][2]=1; m_space[3][0]=0; m_space[3][1]=0; m_space[3][2]=0; if(o_eye.isNull()) MGlobal::displayWarning("Cannot find render camera, use default space."); else zWorks::getTransformWorldNoScale(p_eye.partialPathName(), m_space); XYZ view_dir(-m_space[2][0], -m_space[2][1], -m_space[2][2]); view_dir.normalize(); // additional attribs MStringArray attribArray; cache_attrib.split('.', attribArray); MSelectionList slist; MGlobal::getActiveSelectionList( slist ); MItSelectionList list( slist, MFn::kParticle, &status ); if (MS::kSuccess != status) { displayError( "Could not create selection list iterator"); return status; } if (list.isDone()) { displayError( "No particles selected" ); return MS::kSuccess; } MDagPath fDagPath; MObject component; unsigned npt = 0,acc = 0; for(; !list.isDone(); list.next()) { list.getDagPath (fDagPath, component); MFnParticleSystem ps( fDagPath ); npt += ps.count(); } if(npt < 1) { MGlobal::displayInfo(" zero particle: do nothing "); return MS::kSuccess; } std::list<AParticle *> particles; RGRID *buf = new RGRID[npt]; unsigned *idxb = new unsigned[npt]; float *opab = new float[npt]; float *ageb = new float[npt]; list.reset(); for(; !list.isDone(); list.next()) { list.getDagPath (fDagPath, component); MFnParticleSystem ps( fDagPath ); MVectorArray positions; ps.position( positions ); MVectorArray velarr; ps.velocity( velarr ); MIntArray ids; ps.particleIds(ids); MVectorArray cols; ps.rgb(cols); MDoubleArray opas; ps.opacity(opas); MDoubleArray ages; ps.opacity(ages); for(unsigned i=0; i<positions.length(); i++,acc++ ) { buf[acc].pos.x = positions[i].x; buf[acc].pos.y = positions[i].y; buf[acc].pos.z = positions[i].z; buf[acc].nor.x = velarr[i].x; buf[acc].nor.y = velarr[i].y; buf[acc].nor.z = velarr[i].z; buf[acc].area = def_area; if(ps.hasRgb()) { buf[acc].col.x = cols[i].x; buf[acc].col.y = cols[i].y; buf[acc].col.z = cols[i].z; } else buf[acc].col = XYZ(1,1,1); idxb[acc] = ids[i]; if(ps.hasOpacity ()) opab[acc] = opas[i]; else opab[acc] = 1.f; ageb[acc] = ages[i]; AParticle *pt = new AParticle(); pt->pos.x = positions[i].x; pt->pos.y = positions[i].y; pt->pos.z = positions[i].z; pt->r = def_area; particles.push_back(pt); } } /* Z3DTexture* tree = new Z3DTexture(); tree->setGrid(buf, npt); tree->constructTree(root_center, root_size, max_level); tree->setGridIdData(idxb, npt); tree->setGridOpacityData(opab, npt); tree->setGridAgeData(ageb, npt); MGlobal::displayInfo(MString(" num grid ")+ tree->getNumGrid()); MGlobal::displayInfo(MString(" num voxel ")+ tree->getNumVoxel()); MGlobal::displayInfo(MString(" num leaf ")+ tree->getNumLeaf()); MGlobal::displayInfo(MString(" max level ")+ tree->getMaxLevel()); MGlobal::displayInfo(" calculating voxel volume occlusion..."); tree->occlusionVolume(cloud_os, key_dir, view_dir); MGlobal::displayInfo(" done"); MGlobal::displayInfo(" updating grid distance to neighbour..."); tree->distanceToNeighbour(cache_mindist); MGlobal::displayInfo(" done"); char filename[512]; sprintf( filename, "%s/%s.%d.pmap", cache_path.asChar(), cache_name.asChar(), frame ); MGlobal::displayInfo(MString("PTCMap saved ") + filename); tree->save(filename); delete tree; */ if(!particles.empty()) { GPUOctree *data = new GPUOctree(); data->create(root_center, root_size, 8, particles); MGlobal::displayInfo(MString(" num voxel ")+ data->getNumVoxel()+ MString(" minvar ")+ data->getMinVariation()+ MString(" max level ")+ data->getMaxLevel()+ MString(" filter size ")+ def_area); char filename[512]; sprintf( filename, "%s/%s.%d", cache_path.asChar(), cache_name.asChar(), frame ); data->dumpIndirection(filename); delete data; particles.clear(); } return MS::kSuccess; }
bool collide( const MObject hairSystem, const int follicleIndex, MVectorArray &hairPositions, MVectorArray &hairPositionsLast, const MDoubleArray &hairWidths, const int startIndex, const int endIndex, const double curTime, const double friction, const void *privateData ) { // Get the private data for the collision objects which was returned // from preFrame(). // COLLISION_INFO *ci = (COLLISION_INFO *) privateData; if ( !ci ) { fprintf( stderr,"%s:%d: collide() privateData pointer is NULL\n", __FILE__, __LINE__ ); return( false ); } // If object has no vertices, or hair has no segments, then there is // nothing to collide. In our example, we'll return here, but if you // want to implement your own hair processing such as smoothing or // freeze on the hair, you could proceed and let the processing happen // after the object loop so that the data gets processed even if no // collisions occur. // if ( ci->numObjs <= 0 || hairPositions.length() <= 0 ) { return( true ); } int obj; for ( obj = 0; obj < ci->numObjs; ++obj ) { COLLISION_OBJ *co = &ci->objs[obj]; // For our plug-in example, we just collide the segments of the // hair against the top of the bounding box for the geometry. // In an implementation where you only care about hair falling // downwards onto flat objects, this might be OK. However, in the // most deluxe of implementation, you should do the following: // // o Determine the motion of each face of your collision // object during the time range. // o Step through the follicle, and consider each segment // to be a moving cylinder where the start and end radii // can differ. The radii come from `hairWidths' and the // motion comes from the difference between `hairPositions' // and `hairPositionsLast'. // o Intersect each moving element (e.g. moving triangle // if you have a mesh obect) with each hair segment // e.g. moving cylinder). This intersection may occur // at a point within the frame. (Remember that the // hairPositions[] array holds the DESIRED location where // the hair system wants the hair to go. // o There can be multiple collisions along a hair segment. // Use the first location found and the maximal velocity. // // If a collision is detected, the `hairPositions' array should be // updated. `hairPositionsLast' may also be updated to provide a // dampening effect only. // // Loop through the follicle, starting at the root and advancing // toward the tip. // int numSegments = hairPositions.length() - 1; int seg; for ( seg = 0; seg < numSegments; ++seg ) { // Get the desired position of the segment (i.e. where the // solver is trying to put the hair for the current frame) // and the velocity required to get to that desired position. // // Thus, // P = hairPositions // Desired pos'n at cur frame. // L = hairPositionsLast // Position at prev frame. // V = P - L // Desired velocity of hair. // MVector pStart = hairPositions[seg]; MVector pEnd = hairPositions[seg + 1]; MVector vStart = pStart - hairPositionsLast[seg]; MVector vEnd = pEnd - hairPositionsLast[seg + 1]; // The proper way to time sample is to intersect the moving // segment of width `hairWidths[seg] to hairWidths[seg + 1]' // with the moving collision object. For the purposes of our // demo plug-in, we will simply assume the collision object is // static, the hair segment has zero width, and instead of // intersecting continuously in time, we will sample discrete // steps along the segment. // #define STEPS 4 int step; for ( step = 0; step < STEPS; ++step ) { // Compute the point for this step and its corresponding // velocity. This is a "time swept" point: // p1 = desired position at current time // p0 = position at previous time to achieve desired pos // MVector pCur, pPrev, v; double fracAlongSeg = step / ( (double) STEPS ); v = vStart * ( 1.0 - fracAlongSeg ) + vEnd * fracAlongSeg; MVector p1 = pStart * ( 1.0 - fracAlongSeg ) + pEnd * fracAlongSeg; MVector p0 = p1 - v; // See if BOTH endpoints are outside of the bounding box // on the same side. If so, then the segment cannot // intersect the bounding box. Note that we assume the // bounding box is static. // if ( (p0.x < co->minx && p1.x < co->minx) || (p0.y < co->miny && p1.y < co->miny) || (p0.z < co->minz && p1.z < co->minz) || (p0.x > co->maxx && p1.x > co->maxx) || (p0.y > co->maxy && p1.y > co->maxy) || (p0.z > co->maxz && p1.z > co->maxz) ) { continue; } // For the purposes of this example plug-in, we'll assume // the hair always moves downwards (due to gravity and // thus in the negative Y direction). As such, we only // need to test for collisions with the TOP of the // bounding box. Expanding the example to all 6 sides is // left as an exercise for the reader. // // Remember that p1 is the point at current time, and // p0 is the point at the previous time. Since we assume // the bounding box to be static, this simplifies things. // MVector where(-100000,-100000,-100000); // Loc'n of collision double fracTime; // Time at which collision happens 0..1 if ( fabs( v.y ) < EPSILON // velocity is zero && fabs( p1.y - co->maxy ) < EPSILON ) { // right on the bbox // Velocity is zero and the desired location (p1) is // right on top of the bounding box. // where = p1; fracTime = 1.0; // Collides right at end; } else { fracTime = ( co->maxy - p0.y ) / v.y; if ( fracTime >= 0.0 && fracTime <= 1.0 ) { // Compute the collision of the swept point with the // plane defined by the top of the bounding box. // where = p0 + v * fracTime; } } // If `seg' lies between startIndex and endIndex // we can move it. If its <= startIndex, the root is // locked and if >= endIndex the tip is locked. // if ( seg >= startIndex && seg <= endIndex ) { // Since we are just colliding with the top of the // bounding box, the normal where we hit is (0,1,0). // For the object velocity, we SHOULD measure the // relative motion of the object during the time // interval, but for our example, we'll assume its // not moving (0,0,0). // bool segCollides = false; MVector normal(0.0,1.0,0.0); // normal is always up MVector objectVel(0.0,0.0,0.0); // assume bbox is static // If we get the this point, then the intersection // point `where' is on the plane of the bounding box // top. See if it lies within the actual bounds of the // boxtop, and if so compute the position and velocity // information and apply to the hair segment. // if ( where.x >= co->minx && where.x <= co->maxx && where.z >= co->minz && where.z <= co->maxz && fracTime >= 0.0 && fracTime <= 0.0 ) { // We have a collision at `where' with the plane. // Compute the new velocity for the hair at the // point of collision. // MVector objVelAlongNormal = (objectVel * normal) * normal; MVector objVelAlongTangent = objectVel - objVelAlongNormal; MVector pntVelAlongTangent = v - ( v * normal ) * normal; MVector reflectedPntVelAlongTangent = pntVelAlongTangent * ( 1.0 - friction ) + objVelAlongTangent * friction; MVector newVel = objVelAlongNormal + reflectedPntVelAlongTangent; // Update the hair position. It actually looks // more stable from a simulation standpoint to // just move the closest segment endpoint, but // you are free to experiment. What we'll do in // our example is move the closest segment end- // point by the amount the collided point (where) // has to move to have velocity `newVel' yet still // pass through `where' at time `fracTime'. // if ( fracAlongSeg > 0.5 ) { MVector deltaPos = -newVel * fracTime; hairPositionsLast[seg + 1] += deltaPos; hairPositions[seg + 1] = hairPositionsLast[seg] + newVel; } else { MVector deltaPos = newVel * fracTime; hairPositionsLast[seg] += deltaPos; hairPositions[seg] = hairPositionsLast[seg] + newVel; } segCollides = true; } // Check for segment endpoints that may still be // inside. Note that segments which started out being // totally inside will never collide using the // algorithm we use above, so we'll simply clamp them // here. One might expect an inside-the-bounding-box // test instead. However, this does not work if the // collision object is a very thin object. // bool inside = false; if ( belowCollisionPlane( co, hairPositions[seg] ) ) { hairPositions[seg].y = co->maxy + EPSILON; hairPositionsLast[seg] = hairPositions[seg] - objectVel; inside = true; } if ( belowCollisionPlane( co, hairPositions[seg+1] ) ) { hairPositions[seg+1].y = co->maxy + EPSILON; hairPositionsLast[seg+1] = hairPositions[seg+1] - objectVel; inside = true; } // If we collided, go onto the next segment. // if ( segCollides || inside ) { goto nextSeg; } } } nextSeg:; } } // You could perform any global filtering that you want on the hair // right here. For example: smoothing. This code is independent of // whether or not a collision occurred, and note that collide() is // called even with zero collision objects, so you will be guaranteed // of reaching here once per hair per iteration. // return( true ); }
IECore::DataPtr convert( const MCommandResult &result ) { MStatus s; switch (result.resultType()) { case MCommandResult::kInvalid: { // No result return 0; } case MCommandResult::kInt: { int i; s = result.getResult(i); assert(s); IECore::IntDataPtr data = new IECore::IntData(); data->writable() = i; return data; } case MCommandResult::kIntArray: { MIntArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::IntVectorDataPtr data = new IECore::IntVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { (data->writable())[i] = v[i]; } return data; } case MCommandResult::kDouble: { double d; s = result.getResult(d); assert(s); IECore::FloatDataPtr data = new IECore::FloatData(); data->writable() = static_cast<float>(d); return data; } case MCommandResult::kDoubleArray: { MDoubleArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::DoubleVectorDataPtr data = new IECore::DoubleVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { data->writable()[i] = v[i]; } return data; } case MCommandResult::kString: { MString str; s = result.getResult(str); assert(s); IECore::StringDataPtr data = new IECore::StringData(); data->writable() = std::string(str.asChar()); return data; } case MCommandResult::kStringArray: { MStringArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::StringVectorDataPtr data = new IECore::StringVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { data->writable()[i] = std::string(v[i].asChar()); } return data; } case MCommandResult::kVector: { MVector v; s = result.getResult(v); assert(s); IECore::V3fDataPtr data = new IECore::V3fData(); data->writable() = Imath::V3f(v.x, v.y, v.z); return data; } case MCommandResult::kVectorArray: { MVectorArray v; s = result.getResult(v); assert(s); unsigned sz = v.length(); IECore::V3fVectorDataPtr data = new IECore::V3fVectorData(); data->writable().resize(sz); for (unsigned i = 0; i < sz; i++) { data->writable()[i] = Imath::V3f(v[i].x, v[i].y, v[i].z); } return data; } case MCommandResult::kMatrix: { MDoubleArray v; int numRows, numColumns; s = result.getResult(v, numRows, numColumns); assert(s); if (numRows > 4 || numColumns > 4) { throw IECoreMaya::StatusException( MS::kFailure ); } IECore::M44fDataPtr data = new IECore::M44fData(); for (int i = 0; i < numColumns; i++) { for (int j = 0; j < numRows; j++) { (data->writable())[i][j] = v[i*numRows+j]; } } return data; } case MCommandResult::kMatrixArray: { return 0; } default: assert( false ); return 0; } }
bool SargassoNode::creatRestShape(const MObject & m) { MStatus stat; MFnMesh fmesh(m, &stat); if(!stat) { MGlobal::displayInfo("val is not mesh"); return false; } MObject thisObj = thisMObject(); MPlug pnv(thisObj, atargetNv); const int restNv = pnv.asInt(); if(restNv != fmesh.numVertices()) { MGlobal::displayInfo("target nv not match"); return false; } MPlug pntriv(thisObj, atargetNt); const int restNtriv = pntriv.asInt(); MIntArray triangleCounts, triangleVertices; fmesh.getTriangles(triangleCounts, triangleVertices); if(restNtriv != triangleVertices.length()) { MGlobal::displayInfo("target ntri not match"); return false; } m_mesh->create(restNv, restNtriv/3); MPlug prestp(thisObj, atargetRestP); MObject orestp; prestp.getValue(orestp); MFnPointArrayData frestp(orestp); MPointArray restPArray = frestp.array(); if(restPArray.length() != restNv) { MGlobal::displayInfo("cached target nv not match"); return false; } Vector3F * p = m_mesh->points(); unsigned i=0; for(;i<restNv;i++) p[i].set(restPArray[i].x, restPArray[i].y, restPArray[i].z); MPlug presttri(thisObj, atargetTri); MObject oresttri; presttri.getValue(oresttri); MFnIntArrayData fresttri(oresttri); MIntArray restTriArray = fresttri.array(); if(restTriArray.length() != restNtriv) { MGlobal::displayInfo("cached target ntri not match"); return false; } unsigned * ind = m_mesh->indices(); for(i=0;i<restNtriv;i++) ind[i] = restTriArray[i]; const BoundingBox box = ((AGenericMesh *)m_mesh)->calculateBBox(); AHelper::Info<BoundingBox>("target mesh box", box); m_diff = new TriangleDifference(m_mesh); MPlug ptargetbind(thisObj, atargetBind); MObject otargetbind; ptargetbind.getValue(otargetbind); MFnIntArrayData ftargetbind(otargetbind); MIntArray targetBindArray = ftargetbind.array(); const unsigned nbind = targetBindArray.length(); AHelper::Info<unsigned>("n binded triangles", nbind); std::vector<unsigned> vbind; for(i=0;i<nbind;i++) vbind.push_back(targetBindArray[i]); m_diff->requireQ(vbind); vbind.clear(); MPlug pobjLocal(thisObj, aobjLocal); MObject oobjLocal; pobjLocal.getValue(oobjLocal); MFnVectorArrayData fobjLocal(oobjLocal); MVectorArray localPArray = fobjLocal.array(); m_numObjects = localPArray.length(); AHelper::Info<unsigned>("n constrained objects", m_numObjects); m_localP->create(m_numObjects * 12); Vector3F * lp = localP(); for(i=0;i<m_numObjects;i++) lp[i].set(localPArray[i].x, localPArray[i].y, localPArray[i].z); m_triId->create(m_numObjects * 4); MPlug pobjtri(thisObj, aobjTri); MObject oobjtri; pobjtri.getValue(oobjtri); MFnIntArrayData fobjtri(oobjtri); MIntArray objtriArray = fobjtri.array(); unsigned * tri = objectTriangleInd(); for(i=0;i<m_numObjects;i++) tri[i] = objtriArray[i]; return true; }