void create_subdivided_face(int sdRes, int nV, double *uvs, double *itv, int Tidx, MFloatArray &uA, MFloatArray &vA, MIntArray &uvIdx) { HDS hds; hds.V.setDims(2, nV); memcpy(&hds.V.v[0], uvs, 2*nV*sizeof(double)); hds.nFV.setDims(1, 1); hds.nFV[0] = nV; hds.tip.setDims(1, nV); for (size_t k=0; k<nV; k++) { hds.tip[k] = k; } finalize_HDS(hds); size_t nHE = hds.nHE(), nIHE = hds.nIHE();⟵ hds.T.setDims(1, nHE); hds.itv.setDims(1, nHE); memset(&hds.T.v[0], 0, nHE*sizeof(bool)); if (nV==5) hds.T[Tidx] = 1; memcpy(&hds.itv.v[0], itv, nV*sizeof(double)); // border halfedge tags for (size_t k=nIHE; k<nHE; k++) { hds.itv[k] = hds.itv[hds.twin[k]]; } TCC_MAX::linear_subdivide(hds, sdRes); int sd_nV = hds.nV(); int sd_nIHE = hds.nIHE(); uA.setLength(sd_nV); vA.setLength(sd_nV); for (int k=0; k<sd_nV; k++) { uA[k] = hds.V[2*k+0]; vA[k] = hds.V[2*k+1]; } uvIdx.setLength(sd_nIHE); for (int k=0; k<sd_nIHE; k++) { uvIdx[k]=hds.tip[k]; } }
void peltOverlap::createBoundingCircle(const MStringArray &flattenFaces, MFloatArray ¢er, MFloatArray &radius) // // Description // Represent a face by a center and radius, i.e. // center = {center1u, center1v, center2u, center2v, ... } // radius = {radius1, radius2, ... } // { center.setLength(2 * flattenFaces.length()); radius.setLength(flattenFaces.length()); for(unsigned int i = 0; i < flattenFaces.length(); i++) { MSelectionList selList; selList.add(flattenFaces[i]); MDagPath dagPath; MObject comp; selList.getDagPath(0, dagPath, comp); MItMeshPolygon iter(dagPath, comp); MFloatArray uArray, vArray; iter.getUVs(uArray, vArray); // Loop through all vertices to construct edges/rays float cu = 0.f; float cv = 0.f; unsigned int j; for(j = 0; j < uArray.length(); j++) { cu += uArray[j]; cv += vArray[j]; } cu = cu / uArray.length(); cv = cv / vArray.length(); float rsqr = 0.f; for(j = 0; j < uArray.length(); j++) { float du = uArray[j] - cu; float dv = vArray[j] - cv; float dsqr = du*du + dv*dv; rsqr = dsqr > rsqr ? dsqr : rsqr; } center[2*i] = cu; center[2*i+1] = cv; radius[i] = sqrt(rsqr); } }
bool peltOverlap::createRayGivenFace(const MString &face, MFloatArray &orig, MFloatArray &vec) // // Description // Represent a face by a series of edges(rays), i.e. // orig = {orig1u, orig1v, orig2u, orig2v, ... } // vec = {vec1u, vec1v, vec2u, vec2v, ... } // // return false if no valid uv's. { MSelectionList selList; selList.add(face); MDagPath dagPath; MObject comp; selList.getDagPath(0, dagPath, comp); MItMeshPolygon iter(dagPath, comp); MFloatArray uArray, vArray; iter.getUVs(uArray, vArray); if (uArray.length() == 0 || vArray.length() == 0) return false; orig.setLength(2 * uArray.length()); vec.setLength( 2 * uArray.length()); // Loop through all vertices to construct edges/rays float u = uArray[uArray.length() - 1]; float v = vArray[vArray.length() - 1]; for(unsigned int j = 0; j < uArray.length(); j++) { orig[2*j] = uArray[j]; orig[2*j+1] = vArray[j]; vec[2*j] = u - uArray[j]; vec[2*j+1] = v - vArray[j]; u = uArray[j]; v = vArray[j]; } return true; }
MStatus XmlCacheFormat::readFloatArray( MFloatArray& array, unsigned arraySize ) { MStringArray value; readXmlTagValue(floatArrayTag, value); assert( value.length() == arraySize ); array.setLength( arraySize ); for ( unsigned int i = 0; i < value.length(); i++ ) { array[i] = (float)strtod( value[i].asChar(), NULL ); } return MS::kSuccess; }
// // Change the UVS for the given selection on this mesh object. // /////////////////////////////////////////////////////////////////////////////// MStatus flipUVCmd::getTweakedUVs( const MObject & meshObj, // Object MIntArray & uvList, // UVs to move MFloatArray & uPos, // Moved UVs MFloatArray & vPos ) // Moved UVs { MStatus status; unsigned int i; MFloatArray uArray; MFloatArray vArray; MFnMesh mesh( meshObj ); // Read all UVs from the poly object status = mesh.getUVs(uArray, vArray); CHECK_MSTATUS_AND_RETURN_IT(status); unsigned int nbUvShells = 1; MIntArray uvShellIds; if ((!flipGlobal) || extendToShell) { // First, extract the UV shells. status = mesh.getUvShellsIds(uvShellIds, nbUvShells); CHECK_MSTATUS_AND_RETURN_IT(status); } if (extendToShell) { // Find all shells that have at least a selected UV. bool *selected = new bool[nbUvShells]; for (i = 0 ; i<nbUvShells ; i++) selected[i] = false; for (i = 0 ; i<uvList.length() ; i++) { int indx = uvList[i]; selected[uvShellIds[indx]] = true; } // Now recompute a new list of UVs to modify. unsigned int numUvs = mesh.numUVs(); unsigned int numSelUvs = 0; // Preallocate a buffer, large enough to hold all Ids. This // prevents multiple reallocation from happening when growing // the array. uvList.setLength(numUvs); for (i = 0 ; i<numUvs ; i++) { if (selected[uvShellIds[i]]) uvList[numSelUvs++] = i; } // clamp the array to the proper size. uvList.setLength(numSelUvs); delete [] selected; } // For global flips, just pretend there is only one shell if (flipGlobal) nbUvShells = 1; float *minMax = new float[nbUvShells*4]; for (i = 0 ; i<nbUvShells ; i++) { minMax[4*i+0] = 1e30F; // Min U minMax[4*i+1] = 1e30F; // Min V minMax[4*i+2] = -1e30F; // Max U minMax[4*i+3] = -1e30F; // Max V } // Get the bounding box of the UVs, for each shell if flipGlobal // is true, or for the whole selection if false. for (i = 0 ; i<uvList.length() ; i++) { int indx = uvList[i]; int shellId = 0; if (!flipGlobal) shellId = uvShellIds[indx]; if (uArray[indx] < minMax[4*shellId+0]) minMax[4*shellId+0] = uArray[indx]; if (vArray[indx] < minMax[4*shellId+1]) minMax[4*shellId+1] = vArray[indx]; if (uArray[indx] > minMax[4*shellId+2]) minMax[4*shellId+2] = uArray[indx]; if (vArray[indx] > minMax[4*shellId+3]) minMax[4*shellId+3] = vArray[indx]; } // Adjust the size of the output arrays uPos.setLength(uvList.length()); vPos.setLength(uvList.length()); for (i = 0 ; i<uvList.length() ; i++) { int shellId = 0; int indx = uvList[i]; if (!flipGlobal) shellId = uvShellIds[indx]; // Flip U or V along the bounding box center. if (horizontal) { uPos[i] = minMax[4*shellId+0] + minMax[4*shellId+2] - uArray[indx]; vPos[i] = vArray[indx]; } else { uPos[i] = uArray[indx]; vPos[i] = minMax[4*shellId+1] + minMax[4*shellId+3] - vArray[indx]; } } delete [] minMax; return MS::kSuccess; }
void ToMayaMeshConverter::addUVSet( MFnMesh &fnMesh, const MIntArray &polygonCounts, IECore::ConstMeshPrimitivePtr mesh, const std::string &sPrimVarName, const std::string &tPrimVarName, const std::string &stIdPrimVarName, MString *uvSetName ) const { IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( sPrimVarName ); bool haveS = sIt != mesh->variables.end(); IECore::PrimitiveVariableMap::const_iterator tIt = mesh->variables.find( tPrimVarName ); bool haveT = tIt != mesh->variables.end(); IECore::PrimitiveVariableMap::const_iterator stIdIt = mesh->variables.find( stIdPrimVarName ); bool haveSTId = stIdIt != mesh->variables.end(); if ( haveS && haveT ) { if ( sIt->second.interpolation != IECore::PrimitiveVariable::FaceVarying ) { IECore::msg( IECore::Msg::Warning,"ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported interpolation (expected FaceVarying).") % sPrimVarName ); return; } if ( tIt->second.interpolation != IECore::PrimitiveVariable::FaceVarying ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported interpolation (expected FaceVarying).") % tPrimVarName); return; } if ( !sIt->second.data ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has no data." ) % sPrimVarName ); } if ( !tIt->second.data ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has no data." ) % tPrimVarName ); } /// \todo Employ some M*Array converters to simplify this int numUVs = mesh->variableSize( IECore::PrimitiveVariable::FaceVarying ); IECore::ConstFloatVectorDataPtr u = IECore::runTimeCast<const IECore::FloatVectorData>(sIt->second.data); if ( !u ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported type \"%s\"." ) % sPrimVarName % sIt->second.data->typeName() ); return; } assert( (int)u->readable().size() == numUVs ); IECore::ConstFloatVectorDataPtr v = IECore::runTimeCast<const IECore::FloatVectorData>(tIt->second.data); if ( !v ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported type \"%s\"." ) % tPrimVarName % tIt->second.data->typeName() ); return; } assert( (int)v->readable().size() == numUVs ); const std::vector<float> &uAll = u->readable(); const std::vector<float> &vAll = v->readable(); if ( uvSetName ) { bool setExists = false; MStringArray existingSets; fnMesh.getUVSetNames( existingSets ); for ( unsigned i=0; i < existingSets.length(); ++i ) { if ( *uvSetName == existingSets[i] ) { fnMesh.clearUVs( uvSetName ); setExists = true; break; } } if ( !setExists ) { MDagPath dag; MStatus s = fnMesh.getPath( dag ); if ( s ) { fnMesh.createUVSetWithName( *uvSetName ); } else { fnMesh.createUVSetDataMeshWithName( *uvSetName ); } } } MIntArray uvIds; uvIds.setLength( numUVs ); MFloatArray uArray; MFloatArray vArray; if( haveSTId ) { // Get compressed uv values by matching them with their uvId. IECore::ConstIntVectorDataPtr uvId = IECore::runTimeCast<const IECore::IntVectorData>(stIdIt->second.data); if ( !uvId ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported type \"%s\"." ) % stIdPrimVarName % stIdIt->second.data->typeName() ); return; } const std::vector<int> &uvIdData = uvId->readable(); assert( (int)uvIdData.size() == numUVs ); int highestId = 0; for ( int i = 0; i < numUVs; i++) { uvIds[i] = uvIdData[i]; if( uvIdData[i] > highestId ) { highestId = uvIdData[i]; } } // u and v arrays need only be as long as the number of unique uvIds uArray.setLength( highestId + 1 ); vArray.setLength( highestId + 1 ); for ( int i = 0; i < numUVs; i++ ) { uArray[ uvIds[i] ] = uAll[i]; // FromMayaMeshConverter does the opposite of this vArray[ uvIds[i] ] = 1 - vAll[i]; } } else { // If for some reason we cannot find the uv indices, set the UVs using the old way // the performances in maya won't be good (for weigth painting in particular) uArray.setLength( numUVs ); vArray.setLength( numUVs ); for ( int i = 0; i < numUVs; i++) { uArray[i] = u->readable()[i]; // FromMayaMeshConverter does the opposite of this vArray[i] = 1 - v->readable()[i]; } for ( int i = 0; i < numUVs; i++) { uvIds[i] = i; } } MStatus s = fnMesh.setUVs( uArray, vArray, uvSetName ); if ( !s ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to set UVs." ); return; } s = fnMesh.assignUVs( polygonCounts, uvIds, uvSetName ); if ( !s ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to assign UVs." ); return; } } else if ( haveS ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "Primitive variable \"%s\" found, but not \"%s\"." ) % sPrimVarName % tPrimVarName ); } else if ( haveT ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "Primitive variable \"%s\" found, but not \"%s\"." ) % tPrimVarName % sPrimVarName ); } else { assert( !uvSetName ); } }
MStatus sgBulgeDeformer::deform(MDataBlock& dataBlock, MItGeometry& iter, const MMatrix& mtx, unsigned int index) { MStatus status; float bulgeWeight = dataBlock.inputValue(aBulgeWeight).asFloat(); double bulgeRadius = dataBlock.inputValue(aBulgeRadius).asDouble(); MArrayDataHandle hArrInputs = dataBlock.inputArrayValue(aBulgeInputs); MPointArray allPositions; iter.allPositions(allPositions); if (mem_resetElements) { unsigned int elementCount = hArrInputs.elementCount(); mem_meshInfosInner.resize(mem_maxLogicalIndex); mem_meshInfosOuter.resize(mem_maxLogicalIndex); for (unsigned int i = 0; i < elementCount; i++, hArrInputs.next()) { MDataHandle hInput = hArrInputs.inputValue(); MDataHandle hMatrix = hInput.child(aMatrix); MDataHandle hMesh = hInput.child(aMesh); MMatrix mtxMesh = hMatrix.asMatrix(); MObject oMesh = hMesh.asMesh(); MFnMeshData meshDataInner, meshDataOuter; MObject oMeshInner = meshDataInner.create(); MObject oMeshOuter = meshDataOuter.create(); MFnMesh fnMesh; fnMesh.copy(oMesh, oMeshInner); fnMesh.copy(oMesh, oMeshOuter); sgMeshInfo* newMeshInfoInner = new sgMeshInfo(oMeshInner, hMatrix.asMatrix()); sgMeshInfo* newMeshInfoOuter = new sgMeshInfo(oMeshOuter, hMatrix.asMatrix()); mem_meshInfosInner[hArrInputs.elementIndex()] = newMeshInfoInner; mem_meshInfosOuter[hArrInputs.elementIndex()] = newMeshInfoOuter; } } for (unsigned int i = 0; i < elementCount; i++) { mem_meshInfosInner[i]->setBulge(bulgeWeight, MSpace::kWorld ); } MFloatArray weightList; weightList.setLength(allPositions.length()); for (unsigned int i = 0; i < weightList.length(); i++) weightList[i] = 0.0f; MMatrixArray inputMeshMatrixInverses; inputMeshMatrixInverses.setLength(elementCount); for (unsigned int i = 0; i < elementCount; i++) { inputMeshMatrixInverses[i] = mem_meshInfosInner[i]->matrix(); } for (unsigned int i = 0; i < allPositions.length(); i++) { float resultWeight = 0; for (unsigned int infoIndex = 0; infoIndex < elementCount; infoIndex++) { MPoint localPoint = allPositions[i] * mtx* inputMeshMatrixInverses[infoIndex]; MPoint innerPoint = mem_meshInfosInner[infoIndex]->getClosestPoint(localPoint); MPoint outerPoint = mem_meshInfosOuter[infoIndex]->getClosestPoint(localPoint); MVector innerVector = innerPoint - localPoint; MVector outerVector = outerPoint - localPoint; if (innerVector * outerVector < 0) { double innerLength = innerVector.length(); double outerLength = outerVector.length(); double allLength = innerLength + outerLength; float numerator = float( innerLength * outerLength ); float denominator = float( pow(allLength / 2.0, 2) ); resultWeight = numerator / denominator; } } weightList[i] = resultWeight; } for (unsigned int i = 0; i < allPositions.length(); i++) { allPositions[i] += weightList[i] * MVector(0, 1, 0); } iter.setAllPositions(allPositions); return MS::kSuccess; }
MStatus TransferUV::redoIt() { MStatus status; MFnMesh sourceFnMesh(sourceDagPath); MFnMesh targetFnMesh(targetDagPath); // Get current UV sets and keep them to switch back to them at the last MString currentSourceUVSet = sourceFnMesh.currentUVSetName(); MString currentTargetUVSet = targetFnMesh.currentUVSetName(); // Switch to uv sets specified in flags before starting transfer process // This is required because MFnMesh does not work properly with // "Non-current" UV sets sourceFnMesh.setCurrentUVSetName(sourceUvSet); targetFnMesh.setCurrentUVSetName(targetUvSet); MString* sourceUvSetPtr = &sourceUvSet; MString* targetUvSetPtr = &targetUvSet; MFloatArray sourceUarray; MFloatArray sourceVarray; MIntArray sourceUvCounts; MIntArray sourceUvIds; // Get mesh information for each status = sourceFnMesh.getUVs(sourceUarray, sourceVarray, sourceUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get source UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } status = targetFnMesh.getUVs(originalUarray, originalVarray, targetUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get original UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } status = sourceFnMesh.getAssignedUVs(sourceUvCounts, sourceUvIds, sourceUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get source assigned UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } status = targetFnMesh.getAssignedUVs(originalUvCounts, originalUvIds, targetUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get original assigned UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } // Resize source uv array so it becomes same size as number of targets uv unsigned int targetNumUVs = targetFnMesh.numUVs(); if (targetNumUVs > sourceUarray.length()) { sourceUarray.setLength(targetNumUVs); sourceVarray.setLength(targetNumUVs); } status = targetFnMesh.setUVs(sourceUarray, sourceVarray, targetUvSetPtr); if (MS::kSuccess != status) { MGlobal::displayError("Failed to set source UVs"); return status; } status = targetFnMesh.assignUVs(sourceUvCounts, sourceUvIds, targetUvSetPtr); if (MS::kSuccess != status) { MGlobal::displayError("Failed to assign source UVs"); return status; } // Switch back to originals sourceFnMesh.setCurrentUVSetName(currentSourceUVSet); targetFnMesh.setCurrentUVSetName(currentTargetUVSet); return MS::kSuccess; }
void createUVset(TCCData &tccData, int sdRes, MFloatArray &uArray, MFloatArray &vArray, MFloatArray &sc_uArray, MFloatArray &sc_vArray, MIntArray &uvIdx, float lineThickness) { MFloatArray u4, v4, u5T0, v5T0, u5T1, v5T1, u5T2, v5T2, u5T3, v5T3, u5T4, v5T4; MIntArray id4, id5T0, id5T1, id5T2, id5T3, id5T4; double hds4_uvs[] = { 0,1, 1,1, 1,0, 0,0 }, hds4_itv[] = {1,1,1,1}; create_subdivided_face(sdRes, 4, hds4_uvs, hds4_itv, -1, u4, v4, id4); double hds5T0_uvs[] = { 0,.5, 0,1, 1,1, 1,0, 0,0 }, hds5T0_itv[] = {.5,.5,1,1,1}; create_subdivided_face(sdRes, 5, hds5T0_uvs, hds5T0_itv, 0, u5T0, v5T0, id5T0); double hds5T1_uvs[] = { 0,0, 0,.5, 0,1, 1,1, 1,0 }, hds5T1_itv[] = {1,.5,.5,1,1}; create_subdivided_face(sdRes, 5, hds5T1_uvs, hds5T1_itv, 1, u5T1, v5T1, id5T1); double hds5T2_uvs[] = { 1,0, 0,0, 0,.5, 0,1, 1,1 }, hds5T2_itv[] = {1,1,.5,.5,1}; create_subdivided_face(sdRes, 5, hds5T2_uvs, hds5T2_itv, 2, u5T2, v5T2, id5T2); double hds5T3_uvs[] = { 1,1, 1,0, 0,0, 0,.5, 0,1 }, hds5T3_itv[] = {1,1,1,.5,.5}; create_subdivided_face(sdRes, 5, hds5T3_uvs, hds5T3_itv, 3, u5T3, v5T3, id5T3); double hds5T4_uvs[] = { 0,1, 1,1, 1,0, 0,0, 0,.5 }, hds5T4_itv[] = {.5,1,1,1,.5}; create_subdivided_face(sdRes, 5, hds5T4_uvs, hds5T4_itv, 4, u5T4, v5T4, id5T4); int nV4 = u4.length(), nHE4 = id4.length(); int nV5 = u5T0.length(), nHE5 = id5T0.length(); int nF = tccData.nFV.length(); int nHE = 0, nV = 0; for (int kF = 0; kF<nF; kF++) { switch (tccData.nFV[kF]) { case 4: nV+=nV4; nHE+=nHE4; break; case 5: nV+=nV5; nHE+=nHE5; break; } } uArray.setLength(nV); sc_uArray.setLength(nV); vArray.setLength(nV); sc_vArray.setLength(nV); uvIdx.setLength(nHE); int kHE = 0, sd_kV = 0, sd_kHE = 0; for (int kF = 0; kF<nF; kF++) { int faceConfig = tccData.nFV[kF]; if (faceConfig==5) { for (int kT=0; kT<5; kT++) { if (tccData.T[kHE+kT]) break; faceConfig++; } } // uScale and vScale are chosen to not use T-edges, but match the U/V directions of the patch (convention: first edge gets vScale) switch (faceConfig) { case 4: copy_patch_uvs(sd_kV, sd_kHE, u4, v4, id4, uArray, vArray, tccData.itv[kHE], tccData.itv[kHE+1], sc_uArray, sc_vArray, uvIdx, lineThickness); break; case 5: copy_patch_uvs(sd_kV, sd_kHE, u5T0, v5T0, id5T0, uArray, vArray, tccData.itv[kHE+3], tccData.itv[kHE+4], sc_uArray, sc_vArray, uvIdx, lineThickness); break; case 6: copy_patch_uvs(sd_kV, sd_kHE, u5T1, v5T1, id5T1, uArray, vArray, tccData.itv[kHE+4], tccData.itv[kHE], sc_uArray, sc_vArray, uvIdx, lineThickness); break; case 7: copy_patch_uvs(sd_kV, sd_kHE, u5T2, v5T2, id5T2, uArray, vArray, tccData.itv[kHE], tccData.itv[kHE+1], sc_uArray, sc_vArray, uvIdx, lineThickness); break; case 8: copy_patch_uvs(sd_kV, sd_kHE, u5T3, v5T3, id5T3, uArray, vArray, tccData.itv[kHE+1], tccData.itv[kHE+2], sc_uArray, sc_vArray, uvIdx, lineThickness); break; case 9: copy_patch_uvs(sd_kV, sd_kHE, u5T4, v5T4, id5T4, uArray, vArray, tccData.itv[kHE+2], tccData.itv[kHE+3], sc_uArray, sc_vArray, uvIdx, lineThickness); break; } kHE += tccData.nFV[kF]; } }