void SurfaceAttach::setOutPlugs(MDataBlock dataBlock, const MFnNurbsSurface &fnSurface, const double dataOffset, const bool dataReverse, const short dataGenus, const double dataStaticLength, const MMatrix &dataParentInverse, const short dataDirection) { MTransformationMatrix tfm; MVector t; MEulerRotation r; MArrayDataHandle outputHandle = dataBlock.outputArrayValue(SurfaceAttach::out); std::int32_t count = outputHandle.elementCount(); MDataHandle o; for (unsigned int k = 0; k < count; ++k) { outputHandle.jumpToElement(k); // Get Transformations tfm = this->matrix(fnSurface, outputHandle.elementIndex(), dataOffset, dataReverse, dataGenus, dataStaticLength, dataParentInverse, dataDirection); t = tfm.translation(MSpace::Space::kWorld); r = tfm.eulerRotation(); o = outputHandle.outputValue(); o.child(SurfaceAttach::translate).set(t); o.child(SurfaceAttach::rotate).set(r.x, r.y, r.z); } // Mark Clean dataBlock.setClean(SurfaceAttach::translate); dataBlock.setClean(SurfaceAttach::rotate); dataBlock.setClean(SurfaceAttach::out); }
MStatus ffdPlanar::getBoundingBox( MDataBlock& block, unsigned int multiIndex, MBoundingBox &boundingBoxOut ) { MStatus status = MS::kSuccess; MArrayDataHandle inputHandle = block.outputArrayValue( input ); inputHandle.jumpToElement( multiIndex ); MObject mesh = inputHandle.outputValue().child( inputGeom ).asMesh(); MBoundingBox boundingBox = MBoundingBox(); MFnMesh meshFn( mesh, &status ); MCheckErr( status, "Error getting mesh from mesh object\n" ); MPointArray pointArray = MPointArray(); meshFn.getPoints( pointArray, MSpace::kTransform ); for ( int i = 0; i < pointArray.length(); i++ ) { boundingBox.expand( pointArray[i] ); } boundingBoxOut = boundingBox; return status; }
MStatus RippleDeformer::deform(MDataBlock& dataBlock, MItGeometry& itGeo, const MMatrix& localToWorldMatrix, unsigned int geomIndex) { MStatus status; //get attriubtes as a datahandle float env = dataBlock.inputValue(envelope).asFloat(); float amplitude = dataBlock.inputValue(aAmplitude).asFloat(); float displace = dataBlock.inputValue(aDisplace).asFloat(); //get the mesh //retrieve the handle to the input attribute MArrayDataHandle hInput = dataBlock.outputArrayValue(input, &status); CHECK_MSTATUS_AND_RETURN_IT(status); //get the input array index handle status = hInput.jumpToElement(geomIndex); //get the handle of geomIndex attribute MDataHandle hInputElement = hInput.outputValue(&status); //Get the MObject of the input geometry of geomindex MObject oInputGeom = hInputElement.child(inputGeom).asMesh(); MFnMesh fnMesh(oInputGeom, &status); CHECK_MSTATUS_AND_RETURN_IT(status); if (oInputGeom.isNull()) { return MS::kSuccess; } MFloatVectorArray normals; fnMesh.getVertexNormals(false, normals); MPoint pointPos; float weight; for (; !itGeo.isDone(); itGeo.next()) { //get current point position pointPos = itGeo.position(); weight = weightValue(dataBlock, geomIndex, itGeo.index()); pointPos.x = pointPos.x + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].x * weight * env; pointPos.y = pointPos.y + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].y * weight * env; pointPos.z = pointPos.z + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].z * weight * env; //setPosition itGeo.setPosition(pointPos); } return MS::kSuccess; }
MStatus VolumePushCollider::compute(const MPlug& plug, MDataBlock& dataBlock) { MStatus status; if (plug == aOutput) { // inCollider MArrayDataHandle hInCollider = dataBlock.inputArrayValue(aInCollider); // inVolume MArrayDataHandle hInVolume = dataBlock.inputArrayValue(aInVolume); // output MArrayDataHandle hOutput = dataBlock.inputArrayValue(aOutput); MDoubleArray daValues(hInVolume.elementCount()); for (unsigned int c=0; c<hInCollider.elementCount(); c++) { // Calculate the total of every collider value for each volume status = hInCollider.jumpToArrayElement(c); CHECK_MSTATUS_AND_RETURN_IT(status); MMatrix mInCollider = hInCollider.inputValue().asMatrix(); MTransformationMatrix tmInCollider(mInCollider); MPoint pInCollider = tmInCollider.getTranslation(MSpace::kWorld, &status); CHECK_MSTATUS_AND_RETURN_IT(status); for (unsigned int v=0; v<hInVolume.elementCount(); v++) { // pointMatrixMult status = hInVolume.jumpToArrayElement(v); CHECK_MSTATUS_AND_RETURN_IT(status); MMatrix mInVolume = hInVolume.inputValue().asMatrix(); MVector vVolCollider = pInCollider * mInVolume; // condition if (vVolCollider.length() <= 1.0) { // reverse daValues[v] += abs(1.0 - vVolCollider.length()); } } } for (unsigned int i=0; i<hInVolume.elementCount(); i++) { // set outputs status = hOutput.jumpToArrayElement(i); CHECK_MSTATUS_AND_RETURN_IT(status); hOutput.outputValue().set(daValues[i]); } dataBlock.setClean(plug); } return MS::kSuccess; }
MStatus HesMeshNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; MPlug pnames(thisMObject(), ameshname); const unsigned numMeshes = pnames.numElements(); MString cacheName = data.inputValue( input ).asString(); std::string substitutedCacheName(cacheName.asChar()); EnvVar::replace(substitutedCacheName); MArrayDataHandle meshNameArray = data.inputArrayValue( ameshname ); MArrayDataHandle meshArry = data.outputArrayValue(outMesh, &stat); bool hesStat = false; if( plug.array() == outMesh ) { const unsigned idx = plug.logicalIndex(); if(BaseUtil::IsImporting) hesStat = true; else { if(idx == 0) AHelper::Info<std::string>(" hes mesh open file ", substitutedCacheName ); hesStat = BaseUtil::OpenHes(substitutedCacheName, HDocument::oReadOnly); } if(!hesStat) { AHelper::Info<std::string >("hes mesh cannot open file ", substitutedCacheName); return MS::kFailure; } meshNameArray.jumpToElement(idx); const MString meshName = meshNameArray.inputValue().asString(); if(!BaseUtil::HesDoc->find(meshName.asChar())) { AHelper::Info<MString>(" hes cannot find mesh ", meshName ); return MS::kFailure; } meshArry.jumpToElement(idx); MDataHandle hmesh = meshArry.outputValue(); HPolygonalMesh entryMesh(meshName.asChar() ); APolygonalMesh dataMesh; entryMesh.load(&dataMesh); entryMesh.close(); MFnMeshData dataCreator; MObject outMeshData = dataCreator.create(&stat); if( !stat ) { MGlobal::displayWarning("hes mesh cannot create " + meshName); return MS::kFailure; } AHelper::Info<MString>(" hes init mesh ", meshName); HesperisPolygonalMeshCreator::create(&dataMesh, outMeshData); hmesh.set(outMeshData); data.setClean(plug); if( (idx+1)>=numMeshes ) { if(!BaseUtil::IsImporting) { AHelper::Info<std::string>(" hes mesh close file ", substitutedCacheName ); BaseUtil::CloseHes(); } } } else { return MS::kUnknownParameter; } return MS::kSuccess; }
MStatus AlembicNode::compute(const MPlug & plug, MDataBlock & dataBlock) { MStatus status; // update the frame number to be imported MDataHandle speedHandle = dataBlock.inputValue(mSpeedAttr, &status); double speed = speedHandle.asDouble(); MDataHandle offsetHandle = dataBlock.inputValue(mOffsetAttr, &status); double offset = offsetHandle.asDouble(); MDataHandle timeHandle = dataBlock.inputValue(mTimeAttr, &status); MTime t = timeHandle.asTime(); double inputTime = t.as(MTime::kSeconds); double fps = getFPS(); // scale and offset inputTime. inputTime = computeAdjustedTime(inputTime, speed, offset/fps); // this should be done only once per file if (mFileInitialized == false) { mFileInitialized = true; MDataHandle dataHandle = dataBlock.inputValue(mAbcFileNameAttr); MFileObject fileObject; fileObject.setRawFullName(dataHandle.asString()); MString fileName = fileObject.resolvedFullName(); // TODO, make sure the file name, or list of files create a valid // Alembic IArchive // initialize some flags for plug update mSubDInitialized = false; mPolyInitialized = false; // When an alembic cache will be imported at the first time using // AbcImport, we need to set mIncludeFilterAttr (filterHandle) to be // mIncludeFilterString for later use. When we save a maya scene(.ma) // mIncludeFilterAttr will be saved. Then when we load the saved // .ma file, mIncludeFilterString will be set to be mIncludeFilterAttr. MDataHandle includeFilterHandle = dataBlock.inputValue(mIncludeFilterAttr, &status); MString& includeFilterString = includeFilterHandle.asString(); if (mIncludeFilterString.length() > 0) { includeFilterHandle.set(mIncludeFilterString); dataBlock.setClean(mIncludeFilterAttr); } else if (includeFilterString.length() > 0) { mIncludeFilterString = includeFilterString; } MDataHandle excludeFilterHandle = dataBlock.inputValue(mExcludeFilterAttr, &status); MString& excludeFilterString = excludeFilterHandle.asString(); if (mExcludeFilterString.length() > 0) { excludeFilterHandle.set(mExcludeFilterString); dataBlock.setClean(mExcludeFilterAttr); } else if (excludeFilterString.length() > 0) { mExcludeFilterString = excludeFilterString; } MFnDependencyNode dep(thisMObject()); MPlug allSetsPlug = dep.findPlug("allColorSets"); CreateSceneVisitor visitor(inputTime, !allSetsPlug.isNull(), MObject::kNullObj, CreateSceneVisitor::NONE, "", mIncludeFilterString, mExcludeFilterString); { mData.getFrameRange(mSequenceStartTime, mSequenceEndTime); MDataHandle startFrameHandle = dataBlock.inputValue(mStartFrameAttr, &status); startFrameHandle.set(mSequenceStartTime*fps); MDataHandle endFrameHandle = dataBlock.inputValue(mEndFrameAttr, &status); endFrameHandle.set(mSequenceEndTime*fps); } } // Retime MDataHandle cycleHandle = dataBlock.inputValue(mCycleTypeAttr, &status); short playType = cycleHandle.asShort(); inputTime = computeRetime(inputTime, mSequenceStartTime, mSequenceEndTime, playType); clamp<double>(mSequenceStartTime, mSequenceEndTime, inputTime); // update only when the time lapse is big enough if (fabs(inputTime - mCurTime) > 0.00001) { mOutRead = std::vector<bool>(mOutRead.size(), false); mCurTime = inputTime; } if (plug == mOutPropArrayAttr) { if (mOutRead[0]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[0] = true; unsigned int propSize = static_cast<unsigned int>(mData.mPropList.size()); if (propSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutPropArrayAttr, &status); unsigned int outHandleIndex = 0; MDataHandle outHandle; // for all of the nodes with sampled attributes for (unsigned int i = 0; i < propSize; i++) { // only use the handle if it matches the index. // The index wont line up in the sparse case so we // can just skip that element. if (outArrayHandle.elementIndex() == outHandleIndex++) { outHandle = outArrayHandle.outputValue(); } else { continue; } if (mData.mPropList[i].mArray.valid()) { readProp(mCurTime, mData.mPropList[i].mArray, outHandle); } else if (mData.mPropList[i].mScalar.valid()) { // for visibility only if (mData.mPropList[i].mScalar.getName() == Alembic::AbcGeom::kVisibilityPropertyName) { Alembic::Util::int8_t visVal = 1; mData.mPropList[i].mScalar.get(&visVal, Alembic::Abc::ISampleSelector(mCurTime, Alembic::Abc::ISampleSelector::kNearIndex )); outHandle.setGenericBool(visVal != 0, false); } else { // for all scalar props readProp(mCurTime, mData.mPropList[i].mScalar, outHandle); } } outArrayHandle.next(); } outArrayHandle.setAllClean(); } } else if (plug == mOutTransOpArrayAttr ) { if (mOutRead[1]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[1] = true; unsigned int xformSize = static_cast<unsigned int>(mData.mXformList.size()); if (xformSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutTransOpArrayAttr, &status); MPlug arrayPlug(thisMObject(), mOutTransOpArrayAttr); MDataHandle outHandle; unsigned int outHandleIndex = 0; for (unsigned int i = 0; i < xformSize; i++) { std::vector<double> sampleList; if (mData.mIsComplexXform[i]) { readComplex(mCurTime, mData.mXformList[i], sampleList); } else { Alembic::AbcGeom::XformSample samp; read(mCurTime, mData.mXformList[i], sampleList, samp); } unsigned int sampleSize = (unsigned int)sampleList.size(); for (unsigned int j = 0; j < sampleSize; j++) { // only use the handle if it matches the index. // The index wont line up in the sparse case so we // can just skip that element. if (outArrayHandle.elementIndex() == outHandleIndex++) { outHandle = outArrayHandle.outputValue(&status); } else continue; outArrayHandle.next(); outHandle.set(sampleList[j]); } } outArrayHandle.setAllClean(); } } else if (plug == mOutLocatorPosScaleArrayAttr ) { if (mOutRead[8]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[8] = true; unsigned int locSize = static_cast<unsigned int>(mData.mLocList.size()); if (locSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutLocatorPosScaleArrayAttr, &status); MPlug arrayPlug(thisMObject(), mOutLocatorPosScaleArrayAttr); MDataHandle outHandle; unsigned int outHandleIndex = 0; for (unsigned int i = 0; i < locSize; i++) { std::vector< double > sampleList; read(mCurTime, mData.mLocList[i], sampleList); unsigned int sampleSize = (unsigned int)sampleList.size(); for (unsigned int j = 0; j < sampleSize; j++) { // only use the handle if it matches the index. // The index wont line up in the sparse case so we // can just skip that element. if (outArrayHandle.elementIndex() == outHandleIndex++) { outHandle = outArrayHandle.outputValue(&status); } else continue; outArrayHandle.next(); outHandle.set(sampleList[j]); } } outArrayHandle.setAllClean(); } } else if (plug == mOutSubDArrayAttr) { if (mOutRead[2]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutSubDArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[2] = true; unsigned int subDSize = static_cast<unsigned int>(mData.mSubDList.size()); if (subDSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutSubDArrayAttr, &status); MDataHandle outHandle; for (unsigned int j = 0; j < subDSize; j++) { // these elements can be sparse if they have been deleted if (outArrayHandle.elementIndex() != j) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFnMesh fnMesh(obj); readSubD(mCurTime, fnMesh, obj, mData.mSubDList[j], mSubDInitialized); outHandle.set(obj); } } mSubDInitialized = true; outArrayHandle.setAllClean(); } // for the case where we don't have any nodes, we want to make sure // to push out empty meshes on our connections, this can happen if // the input file was offlined, currently we only need to do this for // meshes as Nurbs, curves, and the other channels don't crash Maya else { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutSubDArrayAttr, &status); if (outArrayHandle.elementCount() > 0) { do { MDataHandle outHandle = outArrayHandle.outputValue(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFloatPointArray emptyVerts; MIntArray emptyCounts; MIntArray emptyConnects; MFnMesh emptyMesh; emptyMesh.create(0, 0, emptyVerts, emptyCounts, emptyConnects, obj); outHandle.set(obj); } } while (outArrayHandle.next() == MS::kSuccess); } mSubDInitialized = true; outArrayHandle.setAllClean(); } } else if (plug == mOutPolyArrayAttr) { if (mOutRead[3]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutPolyArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[3] = true; unsigned int polySize = static_cast<unsigned int>(mData.mPolyMeshList.size()); if (polySize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutPolyArrayAttr, &status); MDataHandle outHandle; for (unsigned int j = 0; j < polySize; j++) { // these elements can be sparse if they have been deleted if (outArrayHandle.elementIndex() != j) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFnMesh fnMesh(obj); readPoly(mCurTime, fnMesh, obj, mData.mPolyMeshList[j], mPolyInitialized); outHandle.set(obj); } } mPolyInitialized = true; outArrayHandle.setAllClean(); } // for the case where we don't have any nodes, we want to make sure // to push out empty meshes on our connections, this can happen if // the input file was offlined, currently we only need to do this for // meshes as Nurbs, curves, and the other channels don't crash Maya else { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutPolyArrayAttr, &status); if (outArrayHandle.elementCount() > 0) { do { MDataHandle outHandle = outArrayHandle.outputValue(&status); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFloatPointArray emptyVerts; MIntArray emptyCounts; MIntArray emptyConnects; MFnMesh emptyMesh; emptyMesh.create(0, 0, emptyVerts, emptyCounts, emptyConnects, obj); outHandle.set(obj); } } while (outArrayHandle.next() == MS::kSuccess); } mPolyInitialized = true; outArrayHandle.setAllClean(); } } else if (plug == mOutCameraArrayAttr) { if (mOutRead[4]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[4] = true; unsigned int cameraSize = static_cast<unsigned int>(mData.mCameraList.size()); if (cameraSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutCameraArrayAttr, &status); MPlug arrayPlug(thisMObject(), mOutCameraArrayAttr); double angleConversion = 1.0; switch (MAngle::uiUnit()) { case MAngle::kRadians: angleConversion = 0.017453292519943295; break; case MAngle::kAngMinutes: angleConversion = 60.0; break; case MAngle::kAngSeconds: angleConversion = 3600.0; break; default: break; } MDataHandle outHandle; unsigned int index = 0; for (unsigned int cameraIndex = 0; cameraIndex < cameraSize; cameraIndex++) { Alembic::AbcGeom::ICamera & cam = mData.mCameraList[cameraIndex]; std::vector<double> array; read(mCurTime, cam, array); for (unsigned int dataIndex = 0; dataIndex < array.size(); dataIndex++, index++) { // skip over sparse elements if (index != outArrayHandle.elementIndex()) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); // not shutter angle index, so not an angle if (dataIndex != 11) { outHandle.set(array[dataIndex]); } else { outHandle.set(array[dataIndex] * angleConversion); } } // for the per camera data handles } // for each camera outArrayHandle.setAllClean(); } } else if (plug == mOutNurbsSurfaceArrayAttr) { if (mOutRead[5]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsSurfaceArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[5] = true; unsigned int nSurfaceSize = static_cast<unsigned int>(mData.mNurbsList.size()); if (nSurfaceSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsSurfaceArrayAttr, &status); MDataHandle outHandle; for (unsigned int j = 0; j < nSurfaceSize; j++) { // these elements can be sparse if they have been deleted if (outArrayHandle.elementIndex() != j) continue; outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kNurbsSurface)) { readNurbs(mCurTime, mData.mNurbsList[j], obj); outHandle.set(obj); } } outArrayHandle.setAllClean(); } } else if (plug == mOutNurbsCurveGrpArrayAttr) { if (mOutRead[6]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsCurveGrpArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[6] = true; unsigned int nCurveGrpSize = static_cast<unsigned int>(mData.mCurvesList.size()); if (nCurveGrpSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsCurveGrpArrayAttr, &status); MDataHandle outHandle; std::vector<MObject> curvesObj; for (unsigned int i = 0; i < nCurveGrpSize; ++i) { readCurves(mCurTime, mData.mCurvesList[i], mData.mNumCurves[i], curvesObj); } std::size_t numChild = curvesObj.size(); // not the best way to do this // only reading bunches of curves based on the connections would be // more efficient when there is a bunch of broken connections for (unsigned int i = 0; i < numChild; i++) { if (outArrayHandle.elementIndex() != i) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); status = outHandle.set(curvesObj[i]); } outArrayHandle.setAllClean(); } } else { return MS::kUnknownParameter; } dataBlock.setClean(plug); return status; }
MStatus PushDeformer::deform(MDataBlock& dataBlock, MItGeometry& itGeo, const MMatrix& localToWorldMatrix, unsigned int geomIndex) { MStatus status; //get attribute handles double bulgeAmount = dataBlock.inputValue(aAmount, &status).asDouble(); CHECK_MSTATUS_AND_RETURN_IT(status); m_taskData.envelope = dataBlock.inputValue(envelope, &status).asFloat(); CHECK_MSTATUS_AND_RETURN_IT(status); bool useStressV = dataBlock.inputValue(aUseStress, &status).asBool(); CHECK_MSTATUS_AND_RETURN_IT(status); int multiThreadingType = dataBlock.inputValue(aMultiThreadingType, &status).asBool(); CHECK_MSTATUS_AND_RETURN_IT(status); if (m_taskData.envelope <= 0.001) { return MS::kSuccess; } // if the use stress plug is turned on pull MDoubleArray stressV; if (useStressV == true) { //pull out the raw data as an Mobject MObject stressMap = dataBlock.inputValue(aStressMap, &status).data(); CHECK_MSTATUS_AND_RETURN_IT(status); MFnDoubleArrayData stressDataFn(stressMap); m_taskData.stressV = stressDataFn.array(); } //retrieve the handle to the output array attribute MArrayDataHandle hInput = dataBlock.outputArrayValue(input, &status); CHECK_MSTATUS_AND_RETURN_IT(status); //get the input array index handle status = hInput.jumpToElement(geomIndex); //get the handle of geomIndex attribute MDataHandle hInputElement = hInput.outputValue(&status); CHECK_MSTATUS_AND_RETURN_IT(status); //Get the MObject of the input geometry of geomindex MObject oInputGeom = hInputElement.child(inputGeom).asMesh(); MFnMesh fnMesh(oInputGeom, &status); CHECK_MSTATUS_AND_RETURN_IT(status); fnMesh.getVertexNormals(false, m_taskData.normals, MSpace::kWorld); itGeo.allPositions(m_taskData.points, MSpace::kWorld); //MGlobal::displayInfo( "test" ); /*for (int i = 0; i < itGeo.count(); i++) { MGlobal::displayInfo( MFnAttribute(weightList).isArray ); }*/ m_taskData.bulgeAmount = bulgeAmount; if(multiThreadingType == 1) { ThreadData* pThreadData = createThreadData( NUM_TASKS, &m_taskData ); MThreadPool::newParallelRegion( createTasks, (void*)pThreadData ); itGeo.setAllPositions(m_taskData.points); delete [] pThreadData; return MS::kSuccess; } else if(multiThreadingType == 2) { tbb::parallel_for(size_t(0), size_t(itGeo.count()), [this](size_t i) { //const float w = weightValue(dataBlock, geomIndex, i); const float w = 1.0; if (m_taskData.useStressV == true && (m_taskData.stressV.length() > 0)) { //deform m_taskData.points[i] += (MVector(m_taskData.normals[i]) * m_taskData.bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[i]); } else { //deform m_taskData.points[i] += m_taskData.normals[i] * m_taskData.bulgeAmount * m_taskData.envelope * w; } }); } // else if(multiThreadingType == 3) #pragma omp parallel for for (int i = 0; i < itGeo.count(); i++) { float w = weightValue(dataBlock, geomIndex, itGeo.index()); if (useStressV == true && (stressV.length() > 0)) { //deform m_taskData.points[i] += (MVector(m_taskData.normals[i]) * bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[i]); } else { //deform m_taskData.points[i] += m_taskData.normals[i] * bulgeAmount * m_taskData.envelope * w; } } else { for (; !itGeo.isDone(); itGeo.next()) { float w = weightValue(dataBlock, geomIndex, itGeo.index()); if (useStressV == true && (stressV.length() > 0)) { //deform m_taskData.points[itGeo.index()] += (MVector(m_taskData.normals[itGeo.index()]) * bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[itGeo.index()]); } else { //deform m_taskData.points[itGeo.index()] += m_taskData.normals[itGeo.index()] * bulgeAmount * m_taskData.envelope * w; } } } itGeo.setAllPositions(m_taskData.points); return MS::kSuccess; }
MStatus snapDeformer::deform(MDataBlock &data, MItGeometry &iter, const MMatrix &mat, unsigned int multiIndex) { MStatus stat; //lets see if we need to do anything MDataHandle DataHandle = data.inputValue(envelope, &stat); float env = DataHandle.asFloat(); if (env == 0) return stat; DataHandle = data.inputValue(weight, &stat); const float weight = DataHandle.asFloat(); if (weight == 0) return stat; env = (env*weight); //space target DataHandle = data.inputValue(space, &stat); int SpaceInt = DataHandle.asInt(); //space source DataHandle = data.inputValue(spaceSource, &stat); int SpaceSourceInt = DataHandle.asInt(); //pointlist MArrayDataHandle pointArrayHandle = data.inputArrayValue(pointList); //snapMesh MFnMesh SnapMesh; DataHandle = data.inputValue(snapMesh, &stat); if (!stat) return Err(stat,"Can't get mesh to snap to"); MObject SnapMeshObj = DataHandle.asMesh(); SnapMesh.setObject(SnapMeshObj); MPointArray snapPoints; if (SpaceSourceInt==0) SnapMesh.getPoints(snapPoints, MSpace::kWorld); else SnapMesh.getPoints(snapPoints, MSpace::kObject); iter.reset(); for ( ; !iter.isDone(); iter.next()) { //check for painted weights float currEnv = env * weightValue(data, multiIndex, iter.index()); //get point to snap to unsigned int index; stat = pointArrayHandle.jumpToElement(iter.index()); if (!stat) index = 0; else { DataHandle = pointArrayHandle.outputValue(); index = DataHandle.asInt(); } if (index != -1) { //calc point location MPoint currPoint; if (snapPoints.length() > index) currPoint = snapPoints[index]; if (SpaceInt == 0) currPoint *= mat.inverse(); if (currEnv !=1) { MPoint p = (currPoint- iter.position()); currPoint = iter.position() + (p*currEnv); } //set point location iter.setPosition(currPoint); } } return stat; }
MStatus CageDeformerNode::deform( MDataBlock& data, MItGeometry& itGeo, const MMatrix &localToWorldMatrix, unsigned int mIndex ) { /// main MStatus status; MThreadUtils::syncNumOpenMPThreads(); // for OpenMP // load cage mesh and other attributes MObject oCageMesh = data.inputValue( aCageMesh ).asMesh(); short blendMode = data.inputValue(aBlendMode).asShort(); bool rotationCosistency = data.inputValue( aRotationConsistency ).asBool(); bool frechetSum = data.inputValue( aFrechetSum ).asBool(); short newConstraintMode = data.inputValue(aConstraintMode).asShort(); double newConstraintWeight = data.inputValue( aConstraintWeight ).asDouble(); if ( oCageMesh.isNull() || blendMode == 99) return MS::kSuccess; short newCageMode = data.inputValue(aCageMode).asShort(); MFnMesh fnCageMesh( oCageMesh, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MPointArray cagePoints; fnCageMesh.getPoints( cagePoints, MSpace::kWorld ); // save initial cage state if (initCagePoints.length() != cagePoints.length()){ initCageMesh = oCageMesh; initCagePoints=cagePoints; } // when cage mode is changed if(newCageMode != cageMode || newConstraintMode != constraintMode || newConstraintWeight != constraintWeight) { cageMode = newCageMode; constraintMode = newConstraintMode; constraintWeight = newConstraintWeight; std::vector<double> tetWeight; // read target mesh data MArrayDataHandle hInput = data.outputArrayValue( input, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); status = hInput.jumpToElement( mIndex ); CHECK_MSTATUS_AND_RETURN_IT( status ); MObject oInputGeom = hInput.outputValue().child( inputGeom ).asMesh(); MFnMesh inputMesh(oInputGeom); inputMesh.getPoints( pts ); numPts=pts.length(); for(int j=0; j<numPts; j++ ) pts[j] *= localToWorldMatrix; MIntArray count; inputMesh.getTriangles( count, meshTriangles ); numTet=meshTriangles.length()/3; std::vector<Matrix4d> P(numTet); tetCenter.resize(numTet); tetMatrixC(pts, meshTriangles, P, tetCenter); PI.resize(numTet); for(int i=0;i<numTet;i++) PI[i] = P[i].inverse(); // prepare cage tetrahedra MFnMesh fnInitCageMesh( initCageMesh, &status ); if(cageMode == 10 || cageMode == 11) // face mode { if(cageMode == 10){ // triangulate faces by MAYA standard MIntArray count; fnInitCageMesh.getTriangles( count, triangles ); tetWeight.resize(triangles.length()/3, 1.0f); }else if(cageMode ==11){ // trianglate faces with more than 3 edges in a symmetric way triangles.clear(); MItMeshPolygon iter(initCageMesh); MIntArray tmp; MVector normal; tetWeight.reserve(4*iter.count()); unsigned int l; for(unsigned int i=0; ! iter.isDone(); i++){ iter.getVertices(tmp); l=tmp.length(); if(l==3){ tetWeight.push_back(1.0); triangles.append(tmp[0]); triangles.append(tmp[1]); triangles.append(tmp[2]); }else{ for(unsigned int j=0;j<l;j++){ tetWeight.push_back((l-2.0)/l); triangles.append(tmp[j]); triangles.append(tmp[(j+1) % l]); triangles.append(tmp[(j+2) % l]); } } iter.next(); } } // face mode compute init matrix numPrb=triangles.length()/3; initMatrix.resize(numPrb); tetMatrix(initCagePoints, triangles, cageMode, initMatrix); // compute weight w.resize(numTet); std::vector< std::vector<double> > idist(numTet); for(int j=0;j<numTet;j++){ idist[j].resize(numPrb); w[j].resize(numPrb); double sidist = 0.0; for(int i=0;i<numPrb;i++){ idist[j][i] = tetWeight[i]/distPtTri(tetCenter[j],initMatrix[i]); sidist += idist[j][i]; } assert(sidist>0.0f); for(int i=0;i<numPrb;i++) w[j][i] = idist[j][i] /sidist; }// face mode end }else if(cageMode == 0 || cageMode == 1){ // vertex mode triangles.clear(); std::vector<int> tetCount(initCagePoints.length()); MItMeshVertex iter(initCageMesh); for(int j=0; ! iter.isDone(); j++){ MIntArray v; iter.getConnectedVertices(v); // at each vertex, construct tetrahedra from connected edges int l=v.length(); if(l==3){ if(isDegenerate(initCagePoints[j],initCagePoints[v[0]],initCagePoints[v[1]],initCagePoints[v[2]]) != 0){ tetCount[j]++; triangles.append(j); triangles.append(v[0]); triangles.append(v[1]); triangles.append(v[2]); } }else{ for(int k=0;k<l;k++){ if(isDegenerate(initCagePoints[j],initCagePoints[v[k]],initCagePoints[v[(k+1) % l]],initCagePoints[v[(k+2) % l]]) != 0){ tetCount[j]++; triangles.append(j); triangles.append(v[k]); triangles.append(v[(k+1) % l]); triangles.append(v[(k+2) % l]); } } } iter.next(); } numPrb=triangles.length()/4; initMatrix.resize(numPrb); tetMatrix(initCagePoints, triangles, cageMode, initMatrix); // vertex mode compute weight w.resize(numTet); std::vector< std::vector<double> > idist(numTet); tetWeight.resize(numPrb); for(int i=0;i<numPrb;i++) tetWeight[i]=1.0/(double)tetCount[triangles[4*i]]; for(int j=0;j<numTet;j++){ idist[j].resize(numPrb); w[j].resize(numPrb); double sidist = 0.0; for(int i=0;i<numPrb;i++){ Vector3d c(initCagePoints[triangles[4*i]].x,initCagePoints[triangles[4*i]].y,initCagePoints[triangles[4*i]].z); idist[j][i] = tetWeight[i] / ((tetCenter[j]-c).squaredNorm()); sidist += idist[j][i]; } assert(sidist>0.0f); for(int i=0;i<numPrb;i++) w[j][i] = idist[j][i] /sidist; } }else if(cageMode == 5 || cageMode == 6 ){ // vertex averaged normal mode triangles.clear(); std::vector<int> tetCount(initCagePoints.length()); MItMeshVertex iter(initCageMesh); for(int j=0; ! iter.isDone(); j++){ MIntArray v; iter.getConnectedVertices(v); int l=v.length(); for(int k=0;k<l;k++){ tetCount[j]++; triangles.append(j); triangles.append(v[k]); triangles.append(v[(k+1) % l]); } iter.next(); } numPrb=triangles.length()/3; initMatrix.resize(numPrb); tetMatrix(initCagePoints, triangles, cageMode, initMatrix); // vertex mode compute weight w.resize(numTet); std::vector< std::vector<double> > idist(numTet); tetWeight.resize(numPrb); for(int i=0;i<numPrb;i++) tetWeight[i]=1.0/(double)tetCount[triangles[3*i]]; for(int j=0;j<numTet;j++){ idist[j].resize(numPrb); w[j].resize(numPrb); double sidist = 0.0; for(int i=0;i<numPrb;i++){ Vector3d c(initCagePoints[triangles[3*i]].x,initCagePoints[triangles[3*i]].y,initCagePoints[triangles[3*i]].z); idist[j][i] = tetWeight[i] / ((tetCenter[j]-c).squaredNorm()); sidist += idist[j][i]; } assert(sidist>0.0f); for(int i=0;i<numPrb;i++) w[j][i] = idist[j][i] /sidist; } }// end of cage setup // find constraint points if(constraintMode == 1){ numConstraint = numPrb; }else{ numConstraint = 1; // at least one constraint is necessary to determine global translation } constraintTet.resize(numConstraint); constraintVector.resize(numConstraint); // for each cage tetrahedra, constraint the point on the mesh with largest weight for(int i=0;i<numConstraint;i++){ constraintTet[i] = 0; for(int j=1;j<numTet;j++){ if(w[j][i] > w[constraintTet[i]][i]){ constraintTet[i] = j; } } constraintVector[i] << tetCenter[constraintTet[i]](0), tetCenter[constraintTet[i]](1), tetCenter[constraintTet[i]](2), 1.0; } // precompute arap solver arapHI(PI, meshTriangles); } // compute deformation if( ! rotationCosistency || numPrb != prevNs.size()){ // clear previous rotation prevThetas.clear(); prevThetas.resize(numPrb, 0.0); prevNs.clear(); prevNs.resize(numPrb, Vector3d::Zero()); } // find affine transformations for tetrahedra std::vector<Matrix4d> cageMatrix(numPrb), SE(numPrb), logSE(numPrb),logAff(numPrb),aff(numPrb); std::vector<Matrix3d> logR(numPrb),R(numPrb),logS(numPrb),logGL(numPrb); std::vector<Vector3d> L(numPrb); std::vector<Vector4d> quat(numPrb); tetMatrix(cagePoints, triangles, cageMode, cageMatrix); for(int i=0; i<numPrb; i++) aff[i]=initMatrix[i].inverse()*cageMatrix[i]; // compute parametrisation if(blendMode == 0 || blendMode == 1 || blendMode == 5) // polarexp or quaternion { for(unsigned int i=0;i<numPrb;i++){ parametriseGL(aff[i].block(0,0,3,3), logS[i] ,R[i]); L[i] = transPart(aff[i]); if(blendMode == 0){ // Rotational log logR[i]=logSOc(R[i], prevThetas[i], prevNs[i]); }else if(blendMode == 1){ // Eucledian log SE[i]=affine(R[i], L[i]); logSE[i]=logSEc(SE[i], prevThetas[i], prevNs[i]); }else if(blendMode == 5){ // quaternion Quaternion<double> Q(R[i].transpose()); quat[i] << Q.x(), Q.y(), Q.z(), Q.w(); } } }else if(blendMode == 2){ //logmatrix3 for(unsigned int i=0;i<numPrb;i++){ logGL[i] = aff[i].block(0,0,3,3).log(); L[i] = transPart(aff[i]); } }else if(blendMode == 3){ // logmatrix4 for(unsigned int i=0;i<numPrb;i++){ logAff[i] = aff[i].log(); } } // compute blended matrices #pragma omp parallel for std::vector<Matrix4d> At(numTet); for(int j=0; j<numTet; j++ ){ if(blendMode==0){ Matrix3d RR=Matrix3d::Zero(); Matrix3d SS=Matrix3d::Zero(); Vector3d l=Vector3d::Zero(); for(unsigned int i=0; i<numPrb; i++){ RR += w[j][i] * logR[i]; SS += w[j][i] * logS[i]; l += w[j][i] * L[i]; } SS = expSym(SS); if(frechetSum){ RR = frechetSO(R, w[j]); }else{ RR = expSO(RR); } At[j] = affine(SS*RR, l); }else if(blendMode==1){ // rigid transformation Matrix4d EE=Matrix4d::Zero(); Matrix3d SS=Matrix3d::Zero(); for(unsigned int i=0; i<numPrb; i++){ EE += w[j][i] * logSE[i]; SS += w[j][i] * logS[i]; } if(frechetSum){ EE = frechetSE(SE, w[j]); }else{ EE = expSE(EE); } At[j] = affine(expSym(SS),Vector3d::Zero())*EE; }else if(blendMode == 2){ //logmatrix3 Matrix3d G=Matrix3d::Zero(); Vector3d l=Vector3d::Zero(); for(unsigned int i=0; i<numPrb; i++){ G += w[j][i] * logGL[i]; l += w[j][i] * L[i]; } At[j] = affine(G.exp(), l); }else if(blendMode == 3){ // logmatrix4 Matrix4d A=Matrix4d::Zero(); for(unsigned int i=0; i<numPrb; i++) A += w[j][i] * logAff[i]; At[j] = A.exp(); }else if(blendMode == 5){ // quaternion Vector4d q=Vector4d::Zero(); Matrix3d SS=Matrix3d::Zero(); Vector3d l=Vector3d::Zero(); for(unsigned int i=0; i<numPrb; i++){ q += w[j][i] * quat[i]; SS += w[j][i] * logS[i]; l += w[j][i] * L[i]; } SS = expSym(SS); Quaternion<double> Q(q); Matrix3d RR = Q.matrix().transpose(); At[j] = affine(SS*RR, l); }else if(blendMode==10){ At[j] = Matrix4d::Zero(); for(unsigned int i=0; i<numPrb; i++){ At[j] += w[j][i] * aff[i]; } } } // compute target vertices position MatrixXd G=MatrixXd::Zero(numTet+numPts,3); arapG(At, PI, meshTriangles, aff, G); MatrixXd Sol = solver.solve(G); for(unsigned int i=0;i<numPts;i++){ pts[i].x=Sol(i,0); pts[i].y=Sol(i,1); pts[i].z=Sol(i,2); pts[i] *= localToWorldMatrix.inverse(); } itGeo.setAllPositions(pts); return MS::kSuccess; }