static bool _GetLightingParam( const MIntArray& intValues, const MFloatArray& floatValues, GfVec4f& paramValue) { bool gotParamValue = false; if (intValues.length() >= 3) { paramValue[0] = intValues[0]; paramValue[1] = intValues[1]; paramValue[2] = intValues[2]; if (intValues.length() > 3) { paramValue[3] = intValues[3]; } gotParamValue = true; } else if (floatValues.length() >= 3) { paramValue[0] = floatValues[0]; paramValue[1] = floatValues[1]; paramValue[2] = floatValues[2]; if (floatValues.length() > 3) { paramValue[3] = floatValues[3]; } gotParamValue = true; } return gotParamValue; }
// #### buildUVList // // Face-varying data expects a list of per-face per-vertex // floats. This method reads the UVs from the mesh and // concatenates them into such a list. // MStatus OsdMeshData::buildUVList( MFnMesh& meshFn, std::vector<float>& uvList ) { MStatus status = MS::kSuccess; MItMeshPolygon polyIt( _meshDagPath ); MFloatArray uArray; MFloatArray vArray; // If user hasn't given us a UV set, use the current one MString *uvSetPtr=NULL; if ( _uvSet.numChars() > 0 ) { if (uvSetNameIsValid(meshFn, _uvSet)) { uvSetPtr = &_uvSet; } else { MGlobal::displayWarning(MString("OpenSubdivShader: uvSet \""+_uvSet+"\" does not exist.")); } } else { uvSetPtr = NULL; } // pull UVs from Maya mesh status = meshFn.getUVs( uArray, vArray, uvSetPtr ); MCHECK_RETURN(status, "OpenSubdivShader: Error reading UVs"); if ( uArray.length() == 0 || vArray.length() == 0 ) { MGlobal::displayWarning("OpenSubdivShader: Mesh has no UVs"); return MS::kFailure; } // list of UV values uvList.clear(); uvList.resize( meshFn.numFaceVertices()*2 ); int uvListIdx = 0; // for each face-vertex copy UVs into list, adjusting for renderman orientation for ( polyIt.reset(); !polyIt.isDone(); polyIt.next() ) { int faceIdx = polyIt.index(); unsigned int numPolyVerts = polyIt.polygonVertexCount(); for ( unsigned int faceVertIdx = 0; faceVertIdx < numPolyVerts; faceVertIdx++ ) { int uvIdx; polyIt.getUVIndex( faceVertIdx, uvIdx, uvSetPtr ); // convert maya UV orientation to renderman orientation uvList[ uvListIdx++ ] = uArray[ uvIdx ]; uvList[ uvListIdx++ ] = 1.0f - vArray[ uvIdx ]; } } return status; }
unsigned int peltOverlap::checkCrossingEdges( MFloatArray &face1Orig, MFloatArray &face1Vec, MFloatArray &face2Orig, MFloatArray &face2Vec ) // Check if there are crossing edges between two faces. Return true // if there are crossing edges and false otherwise. A face is represented // by a series of edges(rays), i.e. // faceOrig[] = {orig1u, orig1v, orig2u, orig2v, ... } // faceVec[] = {vec1u, vec1v, vec2u, vec2v, ... } { unsigned int face1Size = face1Orig.length(); unsigned int face2Size = face2Orig.length(); for (unsigned int i = 0; i < face1Size; i += 2) { float o1x = face1Orig[i]; float o1y = face1Orig[i+1]; float v1x = face1Vec[i]; float v1y = face1Vec[i+1]; float n1x = v1y; float n1y = -v1x; for (unsigned int j = 0; j < face2Size; j += 2) { // Given ray1(O1, V1) and ray2(O2, V2) // Normal of ray1 is (V1.y, V1.x) float o2x = face2Orig[j]; float o2y = face2Orig[j+1]; float v2x = face2Vec[j]; float v2y = face2Vec[j+1]; float n2x = v2y; float n2y = -v2x; // Find t for ray2 // t = [(o1x-o2x)n1x + (o1y-o2y)n1y] / (v2x * n1x + v2y * n1y) float denum = v2x * n1x + v2y * n1y; // Edges are parallel if denum is close to 0. if (fabs(denum) < 0.000001f) continue; float t2 = ((o1x-o2x)* n1x + (o1y-o2y) * n1y) / denum; if (t2 < 0.00001f || t2 > 0.99999f) continue; // Find t for ray1 // t = [(o2x-o1x)n2x + (o2y-o1y)n2y] / (v1x * n2x + v1y * n2y) denum = v1x * n2x + v1y * n2y; // Edges are parallel if denum is close to 0. if (fabs(denum) < 0.000001f) continue; float t1 = ((o2x-o1x)* n2x + (o2y-o1y) * n2y) / denum; // Edges intersect if (t1 > 0.00001f && t1 < 0.99999f) return 1; } } return 0; }
// uScale and vScale switched because first edge pointing in v direction void copy_patch_uvs(int &kV, int &kHE, MFloatArray &u_src, MFloatArray &v_src, MIntArray &uvIdx_src, MFloatArray &u_dst, MFloatArray &v_dst, float vScale, float uScale, MFloatArray &sc_u_dst, MFloatArray &sc_v_dst, MIntArray &uvIdx_dst, float lineThickness) { int nHE = uvIdx_src.length(); for (int k=0; k<nHE; k++) { uvIdx_dst[kHE] = kV + uvIdx_src[k]; // offset by beginning of this block of UVs kHE++; } // float offset_u = (uScale - 1) * 0.5*lineThickness; // float offset_v = (vScale - 1) * 0.5*lineThickness; lineThickness = 0.5 * lineThickness; float offset_u = lineThickness * (uScale - 1.0)/(uScale - 2*lineThickness); float offset_v = lineThickness * (vScale - 1.0)/(vScale - 2*lineThickness); int nV = u_src.length(); for (int k=0; k<nV; k++) { u_dst[kV] = u_src[k] * (1.0 - 2.0*offset_u) + offset_u; v_dst[kV] = v_src[k] * (1.0 - 2.0*offset_v) + offset_v; sc_u_dst[kV] = uScale * u_src[k]; sc_v_dst[kV] = vScale * v_src[k]; kV++; } }
float peltOverlap::area(const MFloatArray &orig) { float sum = 0.f; unsigned int num = orig.length() / 2; for (unsigned int i = 0; i < num; i++) { unsigned int idx = 2 * i; unsigned int idy = (i + 1 ) % num; idy = 2 * idy + 1; unsigned int idy2 = (i + num - 1) % num; idy2 = 2 * idy2 + 1; sum += orig[idx] * (orig[idy] - orig[idy2]); } return fabs(sum) * 0.5f; }
MStatus XmlCacheFormat::writeFloatArray( const MFloatArray& array ) { int size = array.length(); assert(size != 0); writeXmlTagValue(sizeTag,size); startXmlBlock( floatArrayTag ); for(int i = 0; i < size; i++) { writeXmlValue(array[i]); } endXmlBlock(); return MS::kSuccess; }
static bool _GetLightingParam( const MIntArray& intValues, const MFloatArray& floatValues, float& paramValue) { bool gotParamValue = false; if (floatValues.length() > 0) { paramValue = floatValues[0]; gotParamValue = true; } return gotParamValue; }
static bool _GetLightingParam( const MIntArray& intValues, const MFloatArray& floatValues, bool& paramValue) { bool gotParamValue = false; if (intValues.length() > 0) { paramValue = (intValues[0] == 1); gotParamValue = true; } else if (floatValues.length() > 0) { paramValue = GfIsClose(floatValues[0], 1.0f, 1e-5); gotParamValue = true; } return gotParamValue; }
MStatus ColorSplineParameterHandler<S>::doSetValue( IECore::ConstParameterPtr parameter, MPlug &plug ) const { assert( parameter ); typename IECore::TypedParameter< S >::ConstPtr p = IECore::runTimeCast<const IECore::TypedParameter< S > >( parameter ); if( !p ) { return MS::kFailure; } MRampAttribute fnRAttr( plug ); if ( !fnRAttr.isColorRamp() ) { return MS::kFailure; } const S &spline = p->getTypedValue(); MStatus s; MIntArray indicesToReuse; plug.getExistingArrayAttributeIndices( indicesToReuse, &s ); assert( s ); int nextNewLogicalIndex = 0; if( indicesToReuse.length() ) { nextNewLogicalIndex = 1 + *std::max_element( MArrayIter<MIntArray>::begin( indicesToReuse ), MArrayIter<MIntArray>::end( indicesToReuse ) ); } assert( indicesToReuse.length() == fnRAttr.getNumEntries() ); size_t pointsSizeMinus2 = spline.points.size() - 2; unsigned pointIndex = 0; unsigned numExpectedPoints = 0; for ( typename S::PointContainer::const_iterator it = spline.points.begin(); it != spline.points.end(); ++it, ++pointIndex ) { // we commonly double up the endpoints on cortex splines to force interpolation to the end. // maya does this implicitly, so we skip duplicated endpoints when passing the splines into maya. // this avoids users having to be responsible for managing the duplicates, and gives them some consistency // with the splines they edit elsewhere in maya. if( ( pointIndex==1 && *it == *spline.points.begin() ) || ( pointIndex==pointsSizeMinus2 && *it == *spline.points.rbegin() ) ) { continue; } MPlug pointPlug; if( indicesToReuse.length() ) { pointPlug = plug.elementByLogicalIndex( indicesToReuse[0] ); indicesToReuse.remove( 0 ); } else { pointPlug = plug.elementByLogicalIndex( nextNewLogicalIndex++ ); } s = pointPlug.child( 0 ).setValue( it->first ); assert( s ); MPlug colorPlug = pointPlug.child( 1 ); colorPlug.child( 0 ).setValue( it->second[0] ); colorPlug.child( 1 ).setValue( it->second[1] ); colorPlug.child( 2 ).setValue( it->second[2] ); // hardcoding interpolation of 3 (spline) because the MRampAttribute::MInterpolation enum values don't actually // correspond to the necessary plug values at all. s = pointPlug.child( 2 ).setValue( 3 ); assert( s ); numExpectedPoints++; } // delete any of the original indices which we didn't reuse. we can't use MRampAttribute::deleteEntries // here as it's utterly unreliable. if( indicesToReuse.length() ) { MString plugName = plug.name(); MObject node = plug.node(); MFnDagNode fnDAGN( node ); if( fnDAGN.hasObj( node ) ) { plugName = fnDAGN.fullPathName() + "." + plug.partialName(); } for( unsigned i=0; i<indicesToReuse.length(); i++ ) { // using mel because there's no equivalant api method as far as i know. MString command = "removeMultiInstance -b true \"" + plugName + "[" + indicesToReuse[i] + "]\""; s = MGlobal::executeCommand( command ); assert( s ); if( !s ) { return s; } } } #ifndef NDEBUG { assert( fnRAttr.getNumEntries() == numExpectedPoints ); MIntArray indices; MFloatArray positions; MColorArray colors; MIntArray interps; fnRAttr.getEntries( indices, positions, colors, interps, &s ); assert( s ); assert( numExpectedPoints == positions.length() ); assert( numExpectedPoints == colors.length() ); assert( numExpectedPoints == interps.length() ); assert( numExpectedPoints == indices.length() ); for ( unsigned i = 0; i < positions.length(); i++ ) { float position = positions[ i ]; const MVector color( colors[ i ][ 0 ], colors[ i ][ 1 ], colors[ i ][ 2 ] ); bool found = false; for ( typename S::PointContainer::const_iterator it = spline.points.begin(); it != spline.points.end() && !found; ++it ) { MVector color2( it->second[0], it->second[1], it->second[2] ); if ( fabs( it->first - position ) < 1.e-3f && ( color2 - color ).length() < 1.e-3f ) { found = true; } } assert( found ); } } #endif return MS::kSuccess; }
PXR_NAMESPACE_OPEN_SCOPE bool MayaMeshWriter::_GetMeshUVSetData( const MFnMesh& mesh, const MString& uvSetName, VtArray<GfVec2f>* uvArray, TfToken* interpolation, VtArray<int>* assignmentIndices) { MStatus status; // Sanity check first to make sure this UV set even has assigned values // before we attempt to do anything with the data. MIntArray uvCounts, uvIds; status = mesh.getAssignedUVs(uvCounts, uvIds, &uvSetName); if (status != MS::kSuccess) { return false; } if (uvCounts.length() == 0 || uvIds.length() == 0) { return false; } // using itFV.getUV() does not always give us the right answer, so // instead, we have to use itFV.getUVIndex() and use that to index into the // UV set. MFloatArray uArray; MFloatArray vArray; mesh.getUVs(uArray, vArray, &uvSetName); if (uArray.length() != vArray.length()) { return false; } // We'll populate the assignment indices for every face vertex, but we'll // only push values into the data if the face vertex has a value. All face // vertices are initially unassigned/unauthored. const unsigned int numFaceVertices = mesh.numFaceVertices(&status); uvArray->clear(); assignmentIndices->assign((size_t)numFaceVertices, -1); *interpolation = UsdGeomTokens->faceVarying; MItMeshFaceVertex itFV(mesh.object()); unsigned int fvi = 0; for (itFV.reset(); !itFV.isDone(); itFV.next(), ++fvi) { if (!itFV.hasUVs(uvSetName)) { // No UVs for this faceVertex, so leave it unassigned. continue; } int uvIndex; itFV.getUVIndex(uvIndex, &uvSetName); if (uvIndex < 0 || static_cast<size_t>(uvIndex) >= uArray.length()) { return false; } GfVec2f value(uArray[uvIndex], vArray[uvIndex]); uvArray->push_back(value); (*assignmentIndices)[fvi] = uvArray->size() - 1; } PxrUsdMayaUtil::MergeEquivalentIndexedValues(uvArray, assignmentIndices); PxrUsdMayaUtil::CompressFaceVaryingPrimvarIndices(mesh, interpolation, assignmentIndices); return true; }
MStatus exportJointClusterData::doIt( const MArgList& args ) // // Process the command // 1. parse the args // 2. find the jointClusters in the scene // 3. iterate over their members, writing their weight data out to file // { // parse args to get the file name from the command-line // MStatus stat = parseArgs(args); if (stat != MS::kSuccess) { return stat; } // count the processed jointClusters // unsigned int jcCount = 0; // Iterate through graph and search for jointCluster nodes // MItDependencyNodes iter( MFn::kJointCluster); for ( ; !iter.isDone(); iter.next() ) { MObject object = iter.item(); MFnWeightGeometryFilter jointCluster(object); // get the joint driving this cluster // MObject joint = jointForCluster(object); if (joint.isNull()) { displayError("Joint is not attached to cluster."); continue; } MObject deformSet = jointCluster.deformerSet(&stat); CheckError(stat,"Error getting deformer set."); MFnSet setFn(deformSet, &stat); //need the fn to get the members CheckError(stat,"Error getting deformer set fn."); MSelectionList clusterSetList; //get all the members // stat = setFn.getMembers(clusterSetList, true); CheckError(stat,"Could not make member list with getMembers."); // print out the name of joint and the number of associated skins // MFnDependencyNode fnJoint(joint); fprintf(file,"%s %u\n",fnJoint.name().asChar(), clusterSetList.length()); for (unsigned int kk = 0; kk < clusterSetList.length(); ++kk) { MDagPath skinpath; MObject components; MFloatArray weights; clusterSetList.getDagPath(kk,skinpath,components); jointCluster.getWeights(skinpath,components,weights); // print out the path name of the skin & the weight count // fprintf(file, "%s %u\n",skinpath.partialPathName().asChar(), weights.length()); // loop through the components and print their index and weight // unsigned counter =0; MItGeometry gIter(skinpath,components); for (/* nothing */ ; !gIter.isDone() && counter < weights.length(); gIter.next()) { fprintf(file,"%d %f\n",gIter.index(),weights[counter]); counter++; } } jcCount++; } fclose(file); if (0 == jcCount) { displayError("No jointClusters found in this scene."); return MS::kFailure; } return MS::kSuccess; }
void MayaObject::getMeshData(MPointArray& points, MFloatVectorArray& normals, MFloatArray& uArray, MFloatArray& vArray, MIntArray& triPointIndices, MIntArray& triNormalIndices, MIntArray& triUvIndices, MIntArray& triMatIndices) { MStatus stat; MObject meshObject = this->mobject; MMeshSmoothOptions options; MFnMesh tmpMesh(this->mobject, &stat); MFnMeshData meshData; MObject dataObject; MObject smoothedObj; // create smooth mesh if needed if (tmpMesh.findPlug("displaySmoothMesh").asBool()) { stat = tmpMesh.getSmoothMeshDisplayOptions(options); if (stat) { if (!tmpMesh.findPlug("useSmoothPreviewForRender", false, &stat).asBool()) { //Logging::debug(MString("useSmoothPreviewForRender turned off")); int smoothLevel = tmpMesh.findPlug("renderSmoothLevel", false, &stat).asInt(); options.setDivisions(smoothLevel); } if (options.divisions() > 0) { dataObject = meshData.create(); smoothedObj = tmpMesh.generateSmoothMesh(dataObject, &options, &stat); if (stat) { meshObject = smoothedObj; } } } } MFnMesh meshFn(meshObject, &stat); CHECK_MSTATUS(stat); MItMeshPolygon faceIt(meshObject, &stat); CHECK_MSTATUS(stat); meshFn.getPoints(points); meshFn.getNormals(normals, MSpace::kObject); meshFn.getUVs(uArray, vArray); uint numVertices = points.length(); uint numNormals = normals.length(); uint numUvs = uArray.length(); //Logging::debug(MString("numVertices ") + numVertices); //Logging::debug(MString("numNormals ") + numNormals); //Logging::debug(MString("numUvs ") + numUvs); // some meshes may have no uv's // to avoid problems I add a default uv coordinate if (numUvs == 0) { Logging::warning(MString("Object has no uv's: ") + this->shortName); uArray.append(0.0); vArray.append(0.0); } for (uint nid = 0; nid < numNormals; nid++) { if (normals[nid].length() < 0.1f) Logging::warning(MString("Malformed normal in ") + this->shortName); } MPointArray triPoints; MIntArray triVtxIds; MIntArray faceVtxIds; MIntArray faceNormalIds; for (faceIt.reset(); !faceIt.isDone(); faceIt.next()) { int faceId = faceIt.index(); int numTris; faceIt.numTriangles(numTris); faceIt.getVertices(faceVtxIds); int perFaceShadingGroup = 0; if (this->perFaceAssignments.length() > 0) perFaceShadingGroup = this->perFaceAssignments[faceId]; MIntArray faceUVIndices; faceNormalIds.clear(); for (uint vtxId = 0; vtxId < faceVtxIds.length(); vtxId++) { faceNormalIds.append(faceIt.normalIndex(vtxId)); int uvIndex; if (numUvs == 0) { faceUVIndices.append(0); } else{ faceIt.getUVIndex(vtxId, uvIndex); //if (uvIndex > uArray.length()) // Logging::info(MString("-----------------> UV Problem!!! uvIndex ") + uvIndex + " > uvArray in object " + this->shortName); faceUVIndices.append(uvIndex); } } for (int triId = 0; triId < numTris; triId++) { int faceRelIds[3]; faceIt.getTriangle(triId, triPoints, triVtxIds); for (uint triVtxId = 0; triVtxId < 3; triVtxId++) { for (uint faceVtxId = 0; faceVtxId < faceVtxIds.length(); faceVtxId++) { if (faceVtxIds[faceVtxId] == triVtxIds[triVtxId]) { faceRelIds[triVtxId] = faceVtxId; } } } uint vtxId0 = faceVtxIds[faceRelIds[0]]; uint vtxId1 = faceVtxIds[faceRelIds[1]]; uint vtxId2 = faceVtxIds[faceRelIds[2]]; uint normalId0 = faceNormalIds[faceRelIds[0]]; uint normalId1 = faceNormalIds[faceRelIds[1]]; uint normalId2 = faceNormalIds[faceRelIds[2]]; uint uvId0 = faceUVIndices[faceRelIds[0]]; uint uvId1 = faceUVIndices[faceRelIds[1]]; uint uvId2 = faceUVIndices[faceRelIds[2]]; triPointIndices.append(vtxId0); triPointIndices.append(vtxId1); triPointIndices.append(vtxId2); triNormalIndices.append(normalId0); triNormalIndices.append(normalId1); triNormalIndices.append(normalId2); triUvIndices.append(uvId0); triUvIndices.append(uvId1); triUvIndices.append(uvId2); triMatIndices.append(perFaceShadingGroup); //Logging::debug(MString("vtxIds ") + vtxId0 + " " + vtxId1 + " " + vtxId2); //Logging::debug(MString("nIds ") + normalId0 + " " + normalId1 + " " + normalId2); //Logging::debug(MString("uvIds ") + uvId0 + " " + uvId1 + " " + uvId2); } } }
MStatus Mesh::load(MDagPath& meshDag,MDagPath *pDagPath) { MStatus stat; std::vector<MFloatArray> weights; std::vector<MIntArray> Ids; std::vector<MIntArray> jointIds; unsigned int numJoints = 0; std::vector<vertexInfo> vertices; MFloatPointArray points; MFloatVectorArray normals; if (!meshDag.hasFn(MFn::kMesh)) return MS::kFailure; MFnMesh mesh(meshDag); /*{ mesh.getPoints(points,MSpace::kWorld); MPoint pos; mesh.getPoint(1,pos,MSpace::kWorld); for(unsigned i = 0;i < points.length();i++) { MFloatPoint fp = points[i]; float x = fp.x; float y = fp.y; float z = fp.z; fp = fp; } }*/ int numVertices = mesh.numVertices(); vertices.resize(numVertices); weights.resize(numVertices); Ids.resize(numVertices); jointIds.resize(numVertices); // 获取UV坐标集的名称 MStringArray uvsets; int numUVSets = mesh.numUVSets(); if (numUVSets > 0) { stat = mesh.getUVSetNames(uvsets); if (MS::kSuccess != stat) { std::cout << "Error retrieving UV sets names\n"; return MS::kFailure; } } // 保存UV集信息 for (int i=m_uvsets.size(); i<uvsets.length(); i++) { uvset uv; uv.size = 2; uv.name = uvsets[i].asChar(); m_uvsets.push_back(uv); } MStringArray colorSetsNameArray; m_colorSets.clear(); int numColorSets = mesh.numColorSets(); if (numColorSets > 0) { mesh.getColorSetNames(colorSetsNameArray); } for (int i = 0; i != colorSetsNameArray.length(); ++i) { std::string name = colorSetsNameArray[i].asChar(); m_colorSets.push_back(name); } // 检查法线是否反 bool opposite = false; mesh.findPlug("opposite",true).getValue(opposite); // get connected skin cluster (if present) bool foundSkinCluster = false; MItDependencyNodes kDepNodeIt( MFn::kSkinClusterFilter ); for( ;!kDepNodeIt.isDone() && !foundSkinCluster; kDepNodeIt.next()) { MObject kObject = kDepNodeIt.item(); m_pSkinCluster = new MFnSkinCluster(kObject); unsigned int uiNumGeometries = m_pSkinCluster->numOutputConnections(); for(unsigned int uiGeometry = 0; uiGeometry < uiNumGeometries; ++uiGeometry ) { unsigned int uiIndex = m_pSkinCluster->indexForOutputConnection(uiGeometry); MObject kOutputObject = m_pSkinCluster->outputShapeAtIndex(uiIndex); if(kOutputObject == mesh.object()) { foundSkinCluster = true; } else { delete m_pSkinCluster; m_pSkinCluster = NULL; } } // load connected skeleton (if present) if (m_pSkinCluster) { if (!m_pSkeleton) m_pSkeleton = new skeleton(); stat = m_pSkeleton->load(m_pSkinCluster); if (MS::kSuccess != stat) std::cout << "Error loading skeleton data\n"; } else { // breakable; } } // get connected shaders MObjectArray shaders; MIntArray shaderPolygonMapping; stat = mesh.getConnectedShaders(0,shaders,shaderPolygonMapping); if (MS::kSuccess != stat) { std::cout << "Error getting connected shaders\n"; return MS::kFailure; } if (shaders.length() <= 0) { std::cout << "No connected shaders, skipping mesh\n"; return MS::kFailure; } // create a series of arrays of faces for each different submesh std::vector<faceArray> polygonSets; polygonSets.resize(shaders.length()); // Get faces data // prepare vertex table for (int i=0; i<vertices.size(); i++) vertices[i].next = -2; //get vertex positions from mesh data mesh.getPoints(points,MSpace::kWorld); mesh.getNormals(normals,MSpace::kWorld); //get list of vertex weights if (m_pSkinCluster) { MItGeometry iterGeom(meshDag); for (int i=0; !iterGeom.isDone(); iterGeom.next(), i++) { weights[i].clear(); Ids[i].clear(); MObject component = iterGeom.component(); MFloatArray vertexWeights; stat=m_pSkinCluster->getWeights(meshDag,component,vertexWeights,numJoints); int nWeights = vertexWeights.length(); for(int j = 0;j<nWeights;j++) { if(vertexWeights[j] >= 0.00001f || vertexWeights[j] <= -0.00001f ) { // 记录该节点j Ids[i].append(j); weights[i].append(vertexWeights[j]); } } //weights[i]= vertexWeights; if (MS::kSuccess != stat) { std::cout << "Error retrieving vertex weights\n"; } // get ids for the joints if (m_pSkeleton) { jointIds[i].clear(); if(weights[i].length() > 0 ) { MDagPathArray influenceObjs; m_pSkinCluster->influenceObjects(influenceObjs,&stat); if (MS::kSuccess != stat) { std::cout << "Error retrieving influence objects for given skin cluster\n"; } jointIds[i].setLength(weights[i].length()); for (int j=0; j<jointIds[i].length(); j++) { bool foundJoint = false; for (int k=0; k<m_pSkeleton->getJoints().size() && !foundJoint; k++) { if (influenceObjs[Ids[i][j]].partialPathName() == m_pSkeleton->getJoints()[k].name) { foundJoint=true; jointIds[i][j] = m_pSkeleton->getJoints()[k].id; } } } } } } } // create an iterator to go through mesh polygons if (mesh.numPolygons() > 0) { const char *name = mesh.name().asChar(); MItMeshPolygon faceIter(mesh.object(),&stat); if (MS::kSuccess != stat) { std::cout << "Error accessing mesh polygons\n"; return MS::kFailure; } // iterate over mesh polygons for (; !faceIter.isDone(); faceIter.next()) { int numTris=0; faceIter.numTriangles(numTris); // for every triangle composing current polygon extract triangle info for (int iTris=0; iTris<numTris; iTris++) { MPointArray triPoints; MIntArray tempTriVertexIdx,triVertexIdx; int idx; // create a new face to store triangle info face newFace; // extract triangle vertex indices faceIter.getTriangle(iTris,triPoints,tempTriVertexIdx); // convert indices to face-relative indices MIntArray polyIndices; faceIter.getVertices(polyIndices); unsigned int iPoly, iObj; for (iObj=0; iObj < tempTriVertexIdx.length(); ++iObj) { // iPoly is face-relative vertex index for (iPoly=0; iPoly < polyIndices.length(); ++iPoly) { if (tempTriVertexIdx[iObj] == polyIndices[iPoly]) { triVertexIdx.append(iPoly); break; } } } // iterate over triangle's vertices for (int i=0; i<3; i++) { bool different = true; int vtxIdx = faceIter.vertexIndex(triVertexIdx[i]); int nrmIdx = faceIter.normalIndex(triVertexIdx[i]); // get vertex color MColor color; if (faceIter.hasColor(triVertexIdx[i])) { //This method gets the average color of the all the vertices in this face stat = faceIter.getColor(color,triVertexIdx[i]); if (MS::kSuccess != stat) { color = MColor(1,1,1,1); } if (color.r > 1) color.r = 1; if (color.g > 1) color.g = 1; if (color.b > 1) color.b = 1; if (color.a > 1) color.a = 1; } else { color = MColor(1,1,1,1); } if (vertices[vtxIdx].next == -2) // first time we encounter a vertex in this position { // save vertex position points[vtxIdx].cartesianize(); vertices[vtxIdx].pointIdx = vtxIdx; // save vertex normal vertices[vtxIdx].normalIdx = nrmIdx; // save vertex colour vertices[vtxIdx].r = color.r; vertices[vtxIdx].g = color.g; vertices[vtxIdx].b = color.b; vertices[vtxIdx].a = color.a; // save vertex texture coordinates vertices[vtxIdx].u.resize(uvsets.length()); vertices[vtxIdx].v.resize(uvsets.length()); // save vbas vertices[vtxIdx].vba.resize(weights[vtxIdx].length()); for (int j=0; j<weights[vtxIdx].length(); j++) { vertices[vtxIdx].vba[j] = (weights[vtxIdx])[j]; } // save joint ids vertices[vtxIdx].jointIds.resize(jointIds[vtxIdx].length()); for (int j=0; j<jointIds[vtxIdx].length(); j++) { vertices[vtxIdx].jointIds[j] = (jointIds[vtxIdx])[j]; } // save uv sets data for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } vertices[vtxIdx].u[j] = uv[0]; vertices[vtxIdx].v[j] = (-1)*(uv[1]-1); } // save vertex index in face info newFace.v[i] = vtxIdx; // update value of index to next vertex info (-1 means nothing next) vertices[vtxIdx].next = -1; } else // already found at least 1 vertex in this position { // check if a vertex with same attributes has been saved already for (int k=vtxIdx; k!=-1 && different; k=vertices[k].next) { different = false; MFloatVector n1 = normals[vertices[k].normalIdx]; MFloatVector n2 = normals[nrmIdx]; if (n1.x!=n2.x || n1.y!=n2.y || n1.z!=n2.z) { different = true; } if (vertices[k].r!=color.r || vertices[k].g!=color.g || vertices[k].b!= color.b || vertices[k].a!=color.a) { different = true; } for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } uv[1] = (-1)*(uv[1]-1); if (vertices[k].u[j]!=uv[0] || vertices[k].v[j]!=uv[1]) { different = true; } } idx = k; } // if no identical vertex has been saved, then save the vertex info if (different) { vertexInfo vtx; // save vertex position vtx.pointIdx = vtxIdx; // save vertex normal vtx.normalIdx = nrmIdx; // save vertex colour vtx.r = color.r; vtx.g = color.g; vtx.b = color.b; vtx.a = color.a; // save vertex vba vtx.vba.resize(weights[vtxIdx].length()); for (int j=0; j<weights[vtxIdx].length(); j++) { vtx.vba[j] = (weights[vtxIdx])[j]; } // save joint ids vtx.jointIds.resize(jointIds[vtxIdx].length()); for (int j=0; j<jointIds[vtxIdx].length(); j++) { vtx.jointIds[j] = (jointIds[vtxIdx])[j]; } // save vertex texture coordinates vtx.u.resize(uvsets.length()); vtx.v.resize(uvsets.length()); for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } vtx.u[j] = uv[0]; vtx.v[j] = (-1)*(uv[1]-1); } vtx.next = -1; vertices.push_back(vtx); // save vertex index in face info newFace.v[i] = vertices.size()-1; vertices[idx].next = vertices.size()-1; } else { newFace.v[i] = idx; } } } // end iteration of triangle vertices // add face info to the array corresponding to the submesh it belongs // skip faces with no shaders assigned if (shaderPolygonMapping[faceIter.index()] >= 0) polygonSets[shaderPolygonMapping[faceIter.index()]].push_back(newFace); } // end iteration of triangles } } std::cout << "done reading mesh triangles\n"; // create a submesh for every different shader linked to the mesh unsigned shaderLength = shaders.length(); for (int i=0; i<shaderLength; i++) { // check if the submesh has at least 1 triangle if (polygonSets[i].size() > 0) { //create new submesh SubMesh* pSubmesh = new SubMesh(); const char *nm = mesh.name().asChar(); const char *nm1 = mesh.partialPathName().asChar(); const char *nm2 = mesh.parentNamespace().asChar(); const char *nm3 = mesh.fullPathName().asChar(); const char *nm4 = meshDag.fullPathName().asChar(); pSubmesh->m_name = meshDag.partialPathName(); if(pDagPath) pSubmesh->m_name = pDagPath->partialPathName(); const char *szName = pSubmesh->m_name.asChar(); if(shaderLength > 1) { char a[256]; sprintf(a,"%d",i); pSubmesh->m_name += a; } OutputDebugString(pSubmesh->m_name.asChar()); OutputDebugString("\n"); //OutputDebugString(szName); //OutputDebugString("\n"); //load linked shader stat = pSubmesh->loadMaterial(shaders[i],uvsets); if (stat != MS::kSuccess) { MFnDependencyNode shadingGroup(shaders[i]); std::cout << "Error loading submesh linked to shader " << shadingGroup.name().asChar() << "\n"; return MS::kFailure; } //load vertex and face data stat = pSubmesh->load(polygonSets[i],vertices,points,normals,opposite); //add submesh to current mesh m_submeshes.push_back(pSubmesh); } } return MS::kSuccess; }
MStatus Molecule3Cmd::redoIt() { MStatus stat; MDagPath dagPath; MFnMesh meshFn; // Create a ball int nBallPolys; MPointArray ballVerts; MIntArray ballPolyCounts; MIntArray ballPolyConnects; MFloatArray ballUCoords; MFloatArray ballVCoords; MIntArray ballFvUVIDs; genBall( MPoint::origin, ballRodRatio * radius.value(), segs, nBallPolys, ballVerts, ballPolyCounts, ballPolyConnects, true, ballUCoords, ballVCoords, ballFvUVIDs ); unsigned int i, j, vertOffset; MPointArray meshVerts; MPoint p0, p1; MObject objTransform; // Setup for rods int nRodPolys; MPointArray rodVerts; MIntArray rodPolyCounts; MIntArray rodPolyConnects; MFloatArray rodUCoords; MFloatArray rodVCoords; MIntArray rodFvUVIDs; // Setup for newMesh int nNewPolys; MPointArray newVerts; MIntArray newPolyCounts; MIntArray newPolyConnects; MFloatArray newUCoords; MFloatArray newVCoords; MIntArray newFvUVIDs; int uvOffset; MDagModifier dagMod; MFnDagNode dagFn; objTransforms.clear(); // Iterate over the meshes unsigned int mi; for( mi=0; mi < selMeshes.length(); mi++ ) { dagPath = selMeshes[mi]; meshFn.setObject( dagPath ); uvOffset = 0; nNewPolys = 0; newVerts.clear(); newPolyCounts.clear(); newPolyConnects.clear(); newUCoords.clear(); newVCoords.clear(); newFvUVIDs.clear(); // Generate balls meshFn.getPoints( meshVerts, MSpace::kWorld ); for( i=0; i < meshVerts.length(); i++ ) { vertOffset = newVerts.length(); // Add the ball to the new mesh nNewPolys += nBallPolys; // Move the ball vertices to the mesh vertex. Add it to the newMesh for( j=0; j < ballVerts.length(); j++ ) newVerts.append( meshVerts[i] + ballVerts[j] ); for( j=0; j < ballPolyCounts.length(); j++ ) newPolyCounts.append( ballPolyCounts[j] ); for( j=0; j < ballPolyConnects.length(); j++ ) newPolyConnects.append( vertOffset + ballPolyConnects[j] ); // Only add the uv coordinates once, since they are shared // by all balls if( i == 0 ) { for( j=0; j < ballUCoords.length(); j++ ) { newUCoords.append( ballUCoords[j] ); newVCoords.append( ballVCoords[j] ); } } for( j=0; j < ballFvUVIDs.length(); j++ ) { newFvUVIDs.append( uvOffset + ballFvUVIDs[j] ); } } uvOffset = newUCoords.length(); // Generate rods int nRods = 0; MItMeshEdge edgeIter( dagPath ); for( ; !edgeIter.isDone(); edgeIter.next(), nRods++ ) { p0 = edgeIter.point( 0, MSpace::kWorld ); p1 = edgeIter.point( 1, MSpace::kWorld ); // N.B. Generate the uv coordinates only once since they // are referenced by all rods genRod( p0, p1, radius.value(), segs, nRodPolys, rodVerts, rodPolyCounts, rodPolyConnects, nRods == 0, rodUCoords, rodVCoords, rodFvUVIDs ); vertOffset = newVerts.length(); // Add the rod to the mesh nNewPolys += nRodPolys; for( i=0; i < rodVerts.length(); i++ ) newVerts.append( rodVerts[i] ); for( i=0; i < rodPolyCounts.length(); i++ ) newPolyCounts.append( rodPolyCounts[i] ); for( i=0; i < rodPolyConnects.length(); i++ ) newPolyConnects.append( vertOffset + rodPolyConnects[i] ); // First rod if( nRods == 0 ) { // Add rod's uv coordinates to the list for( i=0; i < rodUCoords.length(); i++ ) { newUCoords.append( rodUCoords[i] ); newVCoords.append( rodVCoords[i] ); } } // Set the face-vertex-uvIDs for( i=0; i < rodFvUVIDs.length(); i++ ) { newFvUVIDs.append( uvOffset + rodFvUVIDs[i] ); } } objTransform = meshFn.create( newVerts.length(), nNewPolys, newVerts, newPolyCounts, newPolyConnects, newUCoords, newVCoords, MObject::kNullObj, &stat ); if( !stat ) { MGlobal::displayError( MString( "Unable to create mesh: " ) + stat.errorString() ); return stat; } objTransforms.append( objTransform ); meshFn.assignUVs( newPolyCounts, newFvUVIDs ); meshFn.updateSurface(); // Rename transform node dagFn.setObject( objTransform ); dagFn.setName( "molecule" ); // Put mesh into the initial shading group dagMod.commandToExecute( MString( "sets -e -fe initialShadingGroup " ) + meshFn.name() ); } // Select all the newly created molecule meshes MString cmd( "select -r" ); for( i=0; i < objTransforms.length(); i++ ) { dagFn.setObject( objTransforms[i] ); cmd += " " + dagFn.name(); } dagMod.commandToExecute( cmd ); return dagMod.doIt(); }
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; }
// h�mta all n�dv�ndig data och l�gger det i ett MeshData-objekt, som senare anv�nds vid exportering. bool Exporter::ExtractMeshData(MFnMesh &mesh, UINT index) { MeshData mesh_data; MFloatPointArray points; MFloatVectorArray normals; MSpace::Space world_space = MSpace::kTransform; // DAG-path mesh_data.mesh_path = mesh.dagPath(); // namn och id mesh_data.name = mesh.name(); mesh_data.id = index; std::string name = mesh.partialPathName().asChar(); if (!strcmp(name.substr(0, 5).c_str(), "Blend")){ return true; } // triangulera meshen innan man h�mtar punkterna MString command = "polyTriangulate -ch 1 " + mesh_data.name; if (!MGlobal::executeCommand(command)) { return false; } // h�mta icke-indexerade vertexpunkter if (!mesh.getPoints(points, world_space)) { return false; } for (int i = 0; i < points.length(); i++){ point temppoints = { points[i].x, points[i].y, points[i].z }; vec3 temppurepoints = { points[i].x, points[i].y, points[i].z }; mesh_data.points.push_back(temppoints); mesh_data.purepoints.push_back(temppurepoints); } // h�mta icke-indexerade normaler if (!mesh.getNormals(normals, world_space)) { return false; } for (int i = 0; i < normals.length(); i++){ vec3 tempnormals = { normals[i].x, normals[i].y, normals[i].z }; mesh_data.normals.push_back(tempnormals); } //variabler f�r att mellanlagra uvdata och tangenter/bitangenter MStringArray uvSets; mesh.getUVSetNames(uvSets); uvSet tempUVSet; MFloatArray Us; MFloatArray Vs; vec2 UVs; // iterera �ver uvsets och ta ut koordinater, tangenter och bitangenter for (int i = 0; i < uvSets.length(); i++) { MString currentSet = uvSets[i]; mesh.getUVs(Us, Vs, ¤tSet); for (int a = 0; a < Us.length(); a++){ UVs.u = Us[a]; UVs.v = Vs[a]; //1-Vs in order to get correct UV angles tempUVSet.UVs.push_back(UVs); } mesh.getTangents(tempUVSet.tangents, world_space, ¤tSet); mesh.getBinormals(tempUVSet.binormals, world_space, ¤tSet); mesh_data.uvSets.push_back(tempUVSet); } //itererar �ver trianglar och returnerar ID:n f�r associerade vertiser, normaler och uvset MItMeshPolygon itFaces(mesh.dagPath()); while (!itFaces.isDone()) { face tempface; // printf("%d", itFaces.vertexIndex(0)); // printf(" %d", itFaces.vertexIndex(1)); // printf(" %d\n", itFaces.vertexIndex(2)); int vc = itFaces.polygonVertexCount(); for (int i = 0; i < vc; ++i) { tempface.verts[i].pointID = itFaces.vertexIndex(i); tempface.verts[i].normalID = itFaces.normalIndex(i); for (int k = 0; k < uvSets.length(); ++k) { int temptexCoordsID; itFaces.getUVIndex(i, temptexCoordsID, &uvSets[k]); tempface.verts[i].texCoordsID.push_back(temptexCoordsID); } } mesh_data.faces.push_back(tempface); itFaces.next(); } // l�gg till mesh_data i scen-datan scene_.meshes.push_back(mesh_data); return true; }
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 NifMeshExporterSkyrim::ExportMesh( MObject dagNode ) { //out << "NifTranslator::ExportMesh {"; ComplexShape cs; MStatus stat; MObject mesh; //Find Mesh child of given transform object MFnDagNode nodeFn(dagNode); cs.SetName(this->translatorUtils->MakeNifName(nodeFn.name())); for (int i = 0; i != nodeFn.childCount(); ++i) { // get a handle to the child if (nodeFn.child(i).hasFn(MFn::kMesh)) { MFnMesh tempFn(nodeFn.child(i)); //No history items if (!tempFn.isIntermediateObject()) { //out << "Found a mesh child." << endl; mesh = nodeFn.child(i); break; } } } MFnMesh visibleMeshFn(mesh, &stat); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to create visibleMeshFn."); } //out << visibleMeshFn.name().asChar() << ") {" << endl; MFnMesh meshFn; MObject dataObj; MPlugArray inMeshPlugArray; MPlug childPlug; MPlug geomPlug; MPlug inputPlug; // this will hold the returned vertex positions MPointArray vts; //For now always use the visible mesh meshFn.setObject(mesh); //out << "Use the function set to get the points" << endl; // use the function set to get the points stat = meshFn.getPoints(vts); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get points."); } //Maya won't store any information about objects with no vertices. Just skip it. if (vts.length() == 0) { MGlobal::displayWarning("An object in this scene has no vertices. Nothing will be exported."); return; } vector<WeightedVertex> nif_vts(vts.length()); for (int i = 0; i != vts.length(); ++i) { nif_vts[i].position.x = float(vts[i].x); nif_vts[i].position.y = float(vts[i].y); nif_vts[i].position.z = float(vts[i].z); } //Set vertex info later since it includes skin weights //cs.SetVertices( nif_vts ); //out << "Use the function set to get the colors" << endl; MColorArray myColors; meshFn.getFaceVertexColors(myColors); //out << "Prepare NIF color vector" << endl; vector<Color4> niColors(myColors.length()); for (unsigned int i = 0; i < myColors.length(); ++i) { niColors[i] = Color4(myColors[i].r, myColors[i].g, myColors[i].b, myColors[i].a); } cs.SetColors(niColors); // this will hold the returned vertex positions MFloatVectorArray nmls; //out << "Use the function set to get the normals" << endl; // use the function set to get the normals stat = meshFn.getNormals(nmls, MSpace::kTransform); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get normals"); } //out << "Prepare NIF normal vector" << endl; vector<Vector3> nif_nmls(nmls.length()); for (int i = 0; i != nmls.length(); ++i) { nif_nmls[i].x = float(nmls[i].x); nif_nmls[i].y = float(nmls[i].y); nif_nmls[i].z = float(nmls[i].z); } cs.SetNormals(nif_nmls); //out << "Use the function set to get the UV set names" << endl; MStringArray uvSetNames; MString baseUVSet; MFloatArray myUCoords; MFloatArray myVCoords; bool has_uvs = false; // get the names of the uv sets on the mesh meshFn.getUVSetNames(uvSetNames); vector<TexCoordSet> nif_uvs; //Record assotiation between name and uv set index for later map<string, int> uvSetNums; int set_num = 0; for (unsigned int i = 0; i < uvSetNames.length(); ++i) { if (meshFn.numUVs(uvSetNames[i]) > 0) { TexType tt; string set_name = uvSetNames[i].asChar(); if (set_name == "base" || set_name == "map1") { tt = BASE_MAP; } else if (set_name == "dark") { tt = DARK_MAP; } else if (set_name == "detail") { tt = DETAIL_MAP; } else if (set_name == "gloss") { tt = GLOSS_MAP; } else if (set_name == "glow") { tt = GLOW_MAP; } else if (set_name == "bump") { tt = BUMP_MAP; } else if (set_name == "decal0") { tt = DECAL_0_MAP; } else if (set_name == "decal1") { tt = DECAL_1_MAP; } else { tt = BASE_MAP; } //Record the assotiation uvSetNums[set_name] = set_num; //Get the UVs meshFn.getUVs(myUCoords, myVCoords, &uvSetNames[i]); //Make sure this set actually has some UVs in it. Maya sometimes returns empty UV sets. if (myUCoords.length() == 0) { continue; } //Store the data TexCoordSet tcs; tcs.texType = tt; tcs.texCoords.resize(myUCoords.length()); for (unsigned int j = 0; j < myUCoords.length(); ++j) { tcs.texCoords[j].u = myUCoords[j]; //Flip the V coords tcs.texCoords[j].v = 1.0f - myVCoords[j]; } nif_uvs.push_back(tcs); baseUVSet = uvSetNames[i]; has_uvs = true; set_num++; } } cs.SetTexCoordSets(nif_uvs); // this will hold references to the shaders used on the meshes MObjectArray Shaders; // this is used to hold indices to the materials returned in the object array MIntArray FaceIndices; //out << "Get the connected shaders" << endl; // get the shaders used by the i'th mesh instance // Assume this is not instanced for now // TODO support instancing properly stat = visibleMeshFn.getConnectedShaders(0, Shaders, FaceIndices); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get connected shader list."); } vector<ComplexFace> nif_faces; //Add shaders to propGroup array vector< vector<NiPropertyRef> > propGroups; for (unsigned int shader_num = 0; shader_num < Shaders.length(); ++shader_num) { //Maya sometimes lists shaders that are not actually attached to any face. Disregard them. bool shader_is_used = false; for (size_t f = 0; f < FaceIndices.length(); ++f) { if (FaceIndices[f] == shader_num) { shader_is_used = true; break; } } if (shader_is_used == false) { //Shader isn't actually used, so continue to the next one. continue; } //out << "Found attached shader: "; //Attach all properties previously associated with this shader to //this NiTriShape MFnDependencyNode fnDep(Shaders[shader_num]); //Find the shader that this shading group connects to MPlug p = fnDep.findPlug("surfaceShader"); MPlugArray plugs; p.connectedTo(plugs, true, false); for (unsigned int i = 0; i < plugs.length(); ++i) { if (plugs[i].node().hasFn(MFn::kLambert)) { fnDep.setObject(plugs[i].node()); break; } } //out << fnDep.name().asChar() << endl; vector<NiPropertyRef> niProps = this->translatorData->shaders[fnDep.name().asChar()]; propGroups.push_back(niProps); } cs.SetPropGroups(propGroups); //out << "Export vertex and normal data" << endl; // attach an iterator to the mesh MItMeshPolygon itPoly(mesh, &stat); if (stat != MS::kSuccess) { throw runtime_error("Failed to create polygon iterator."); } // Create a list of faces with vertex IDs, and duplicate normals so they have the same ID for (; !itPoly.isDone(); itPoly.next()) { int poly_vert_count = itPoly.polygonVertexCount(&stat); if (stat != MS::kSuccess) { throw runtime_error("Failed to get vertex count."); } //Ignore polygons with less than 3 vertices if (poly_vert_count < 3) { continue; } ComplexFace cf; //Assume all faces use material 0 for now cf.propGroupIndex = 0; for (int i = 0; i < poly_vert_count; ++i) { ComplexPoint cp; cp.vertexIndex = itPoly.vertexIndex(i); cp.normalIndex = itPoly.normalIndex(i); if (niColors.size() > 0) { int color_index; stat = meshFn.getFaceVertexColorIndex(itPoly.index(), i, color_index); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get vertex color."); } cp.colorIndex = color_index; } //Get the UV set names used by this particular vertex MStringArray vertUvSetNames; itPoly.getUVSetNames(vertUvSetNames); for (unsigned int j = 0; j < vertUvSetNames.length(); ++j) { TexCoordIndex tci; tci.texCoordSetIndex = uvSetNums[vertUvSetNames[j].asChar()]; int uv_index; itPoly.getUVIndex(i, uv_index, &vertUvSetNames[j]); tci.texCoordIndex = uv_index; cp.texCoordIndices.push_back(tci); } cf.points.push_back(cp); } nif_faces.push_back(cf); } //Set shader/face association if (nif_faces.size() != FaceIndices.length()) { throw runtime_error("Num faces found do not match num faces reported."); } for (unsigned int face_index = 0; face_index < nif_faces.size(); ++face_index) { nif_faces[face_index].propGroupIndex = FaceIndices[face_index]; } cs.SetFaces(nif_faces); //--Skin Processing--// //Look up any skin clusters if (this->translatorData->meshClusters.find(visibleMeshFn.fullPathName().asChar()) != this->translatorData->meshClusters.end()) { const vector<MObject> & clusters = this->translatorData->meshClusters[visibleMeshFn.fullPathName().asChar()]; if (clusters.size() > 1) { throw runtime_error("Objects with multiple skin clusters affecting them are not currently supported. Try deleting the history and re-binding them."); } vector<MObject>::const_iterator cluster = clusters.begin(); if (cluster->isNull() != true) { MFnSkinCluster clusterFn(*cluster); //out << "Processing skin..." << endl; //Get path to visible mesh MDagPath meshPath; visibleMeshFn.getPath(meshPath); //out << "Getting a list of all verticies in this mesh" << endl; //Get a list of all vertices in this mesh MFnSingleIndexedComponent compFn; MObject vertices = compFn.create(MFn::kMeshVertComponent); MItGeometry gIt(meshPath); MIntArray vertex_indices(gIt.count()); for (int vert_index = 0; vert_index < gIt.count(); ++vert_index) { vertex_indices[vert_index] = vert_index; } compFn.addElements(vertex_indices); //out << "Getting Influences" << endl; //Get influences MDagPathArray myBones; clusterFn.influenceObjects(myBones, &stat); //out << "Creating a list of NiNodeRefs of influences." << endl; //Create list of NiNodeRefs of influences vector<NiNodeRef> niBones(myBones.length()); for (unsigned int bone_index = 0; bone_index < niBones.size(); ++bone_index) { const char* boneName = myBones[bone_index].fullPathName().asChar(); if (this->translatorData->nodes.find(myBones[bone_index].fullPathName().asChar()) == this->translatorData->nodes.end()) { //There is a problem; one of the joints was not exported. Abort. throw runtime_error("One of the joints necessary to export a bound skin was not exported."); } niBones[bone_index] = this->translatorData->nodes[myBones[bone_index].fullPathName().asChar()]; } //out << "Getting weights from Maya" << endl; //Get weights from Maya MDoubleArray myWeights; unsigned int bone_count = myBones.length(); stat = clusterFn.getWeights(meshPath, vertices, myWeights, bone_count); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get vertex weights."); } //out << "Setting skin influence list in ComplexShape" << endl; //Set skin information in ComplexShape cs.SetSkinInfluences(niBones); //out << "Adding weights to ComplexShape vertices" << endl; //out << "Number of weights: " << myWeights.length() << endl; //out << "Number of bones: " << myBones.length() << endl; //out << "Number of Maya vertices: " << gIt.count() << endl; //out << "Number of NIF vertices: " << int(nif_vts.size()) << endl; unsigned int weight_index = 0; SkinInfluence sk; for (unsigned int vert_index = 0; vert_index < nif_vts.size(); ++vert_index) { for (unsigned int bone_index = 0; bone_index < myBones.length(); ++bone_index) { //out << "vert_index: " << vert_index << " bone_index: " << bone_index << " weight_index: " << weight_index << endl; // Only bother with weights that are significant if (myWeights[weight_index] > 0.0f) { sk.influenceIndex = bone_index; sk.weight = float(myWeights[weight_index]); nif_vts[vert_index].weights.push_back(sk); } ++weight_index; } } } MPlugArray connected_dismember_plugs; MObjectArray dismember_nodes; meshFn.findPlug("message").connectedTo(connected_dismember_plugs, false, true); bool has_valid_dismemember_partitions = true; int faces_count = cs.GetFaces().size(); int current_face_index; vector<BodyPartList> body_parts_list; vector<uint> dismember_faces(faces_count, 0); for (int x = 0; x < connected_dismember_plugs.length(); x++) { MFnDependencyNode dependency_node(connected_dismember_plugs[x].node()); if (dependency_node.typeName() == "nifDismemberPartition") { dismember_nodes.append(dependency_node.object()); } } if (dismember_nodes.length() == 0) { has_valid_dismemember_partitions = false; } else { int blind_data_id; int blind_data_value; MStatus status; MPlug target_faces_plug; MItMeshPolygon it_polygons(meshFn.object()); MString mel_command; MStringArray current_body_parts_flags; MFnDependencyNode current_dismember_node; MFnDependencyNode current_blind_data_node; //Naive sort here, there is no reason and is extremely undesirable and not recommended to have more //than 10-20 dismember partitions out of many reasons, so it's okay here //as it makes the code easier to understand vector<int> dismember_nodes_id(dismember_nodes.length(), -1); for (int x = 0; x < dismember_nodes.length(); x++) { current_dismember_node.setObject(dismember_nodes[x]); connected_dismember_plugs.clear(); current_dismember_node.findPlug("targetFaces").connectedTo(connected_dismember_plugs, true, false); if (connected_dismember_plugs.length() == 0) { has_valid_dismemember_partitions = false; break; } current_blind_data_node.setObject(connected_dismember_plugs[0].node()); dismember_nodes_id[x] = current_blind_data_node.findPlug("typeId").asInt(); } for (int x = 0; x < dismember_nodes.length() - 1; x++) { for (int y = x + 1; y < dismember_nodes.length(); y++) { if (dismember_nodes_id[x] > dismember_nodes_id[y]) { MObject aux = dismember_nodes[x]; blind_data_id = dismember_nodes_id[x]; dismember_nodes[x] = dismember_nodes[y]; dismember_nodes_id[x] = dismember_nodes_id[y]; dismember_nodes[y] = aux; dismember_nodes_id[y] = blind_data_id; } } } for (int x = 0; x < dismember_nodes.length(); x++) { current_dismember_node.setObject(dismember_nodes[x]); target_faces_plug = current_dismember_node.findPlug("targetFaces"); connected_dismember_plugs.clear(); target_faces_plug.connectedTo(connected_dismember_plugs, true, false); if (connected_dismember_plugs.length() > 0) { current_blind_data_node.setObject(connected_dismember_plugs[0].node()); current_face_index = 0; blind_data_id = current_blind_data_node.findPlug("typeId").asInt(); for (it_polygons.reset(); !it_polygons.isDone(); it_polygons.next()) { if (it_polygons.polygonVertexCount() >= 3) { status = meshFn.getIntBlindData(it_polygons.index(), MFn::Type::kMeshPolygonComponent, blind_data_id, "dismemberValue", blind_data_value); if (status == MStatus::kSuccess && blind_data_value == 1 && meshFn.hasBlindDataComponentId(it_polygons.index(), MFn::Type::kMeshPolygonComponent, blind_data_id)) { dismember_faces[current_face_index] = x; } current_face_index++; } } } else { has_valid_dismemember_partitions = false; break; } mel_command = "getAttr "; mel_command += current_dismember_node.name(); mel_command += ".bodyPartsFlags"; status = MGlobal::executeCommand(mel_command, current_body_parts_flags); BSDismemberBodyPartType body_part_type = NifDismemberPartition::stringArrayToBodyPartType(current_body_parts_flags); current_body_parts_flags.clear(); mel_command = "getAttr "; mel_command += current_dismember_node.name(); mel_command += ".partsFlags"; status = MGlobal::executeCommand(mel_command, current_body_parts_flags); BSPartFlag part_type = NifDismemberPartition::stringArrayToPart(current_body_parts_flags); current_body_parts_flags.clear(); BodyPartList body_part; body_part.bodyPart = body_part_type; body_part.partFlag = part_type; body_parts_list.push_back(body_part); } } if (has_valid_dismemember_partitions == false) { MGlobal::displayWarning("No proper dismember partitions, generating default ones for " + meshFn.name()); for (int x = 0; x < dismember_faces.size(); x++) { dismember_faces[x] = 0; } BodyPartList body_part; body_part.bodyPart = (BSDismemberBodyPartType)0; body_part.partFlag = (BSPartFlag)(PF_EDITOR_VISIBLE | PF_START_NET_BONESET); body_parts_list.clear(); body_parts_list.push_back(body_part); } cs.SetDismemberPartitionsBodyParts(body_parts_list); cs.SetDismemberPartitionsFaces(dismember_faces); } //out << "Setting vertex info" << endl; //Set vertex info now that any skins have been processed cs.SetVertices(nif_vts); //ComplexShape is now complete, so split it //Get parent NiNodeRef parNode = this->translatorUtils->GetDAGParent(dagNode); Matrix44 transform = Matrix44::IDENTITY; vector<NiNodeRef> influences = cs.GetSkinInfluences(); if (influences.size() > 0) { //This is a skin, so we use the common ancestor of all influences //as the parent vector<NiAVObjectRef> objects; for (size_t i = 0; i < influences.size(); ++i) { objects.push_back(StaticCast<NiAVObject>(influences[i])); } //Get world transform of existing parent Matrix44 oldParWorld = parNode->GetWorldTransform(); //Set new parent node parNode = FindCommonAncestor(objects); transform = oldParWorld * parNode->GetWorldTransform().Inverse(); } //Get transform using temporary NiAVObject NiAVObjectRef tempAV = new NiAVObject; this->nodeExporter->ExportAV(tempAV, dagNode); NiAVObjectRef avObj; if (this->translatorOptions->exportTangentSpace == "falloutskyrimtangentspace") { //out << "Split ComplexShape from " << meshFn.name().asChar() << endl; avObj = cs.Split(parNode, tempAV->GetLocalTransform() * transform, this->translatorOptions->exportBonesPerSkinPartition, this->translatorOptions->exportAsTriStrips, true, this->translatorOptions->exportMinimumVertexWeight, 16); } else { avObj = cs.Split(parNode, tempAV->GetLocalTransform() * transform, this->translatorOptions->exportBonesPerSkinPartition, this->translatorOptions->exportAsTriStrips, false, this->translatorOptions->exportMinimumVertexWeight); } //out << "Get the NiAVObject portion of the root of the split" <<endl; //Get the NiAVObject portion of the root of the split avObj->SetName(tempAV->GetName()); avObj->SetVisibility(tempAV->GetVisibility()); avObj->SetFlags(tempAV->GetFlags()); //If polygon mesh is hidden, hide tri_shape MPlug vis = visibleMeshFn.findPlug(MString("visibility")); bool visibility; vis.getValue(visibility); NiNodeRef splitRoot = DynamicCast<NiNode>(avObj); if (splitRoot != NULL) { //Root is a NiNode with NiTriBasedGeom children. vector<NiAVObjectRef> children = splitRoot->GetChildren(); for (unsigned c = 0; c < children.size(); ++c) { //Set the default collision propogation flag to "use triangles" children[c]->SetFlags(2); // Make the mesh invisible if necessary if (visibility == false) { children[c]->SetVisibility(false); } } } else { //Root must be a NiTriBasedGeom. Make it invisible if necessary if (visibility == false) { avObj->SetVisibility(false); } } }
// Maps vertex points in uv coordinates (uPoints and vPoints) onto plane and creates a new mesh // Only works with planes with the local normal along the y-axis for now (default Maya polyplane) MStatus SplitFromImage::addPlaneSubMesh(MObject &object, MFloatArray uPoints, MFloatArray vPoints, const MFnMesh &planeMesh) { if(uPoints.length() != vPoints.length()) return MS::kFailure; MPointArray planePoints; MIntArray planeVertexCount; MIntArray planeVertexList; planeMesh.getPoints(planePoints); planeMesh.getVertices(planeVertexCount, planeVertexList); cout << "planeVertexCount: " << planeVertexCount.length() << endl; cout << "planeVertexList: " << planeVertexList.length() << endl; double minX, minZ, maxX, maxZ; minX = minZ = 100000; maxX = maxZ = -100000; // Find min and max points of the plane for(unsigned int i = 0; i < planePoints.length(); i++) { double x = planePoints[i].x; double z = planePoints[i].z; if(planePoints[i].x < minX) minX = x; if(planePoints[i].x > maxX) maxX = x; if(planePoints[i].z < minZ) minZ = x; if(planePoints[i].z > maxZ) maxZ = z; } // Set plane's corner pos and width and height double planeX = minX; double planeY = minZ; double planeWidth = maxX - minX; double planeHeight = maxZ - minZ; // Prepare stuff for MFnMesh int numVertices = uPoints.length(); int numPolygons = 1; MPointArray pointArray; int polygon_counts[1] = {numVertices}; MIntArray polygonCounts(polygon_counts, 1); int *polygon_connects = new int[numVertices]; for(int i = 0; i < numVertices; i++) { polygon_connects[i] = i; MPoint point(planeX + planeWidth * uPoints[i], 0, planeY + planeHeight * vPoints[i]); pointArray.append(point); } MIntArray polygonConnects(polygon_connects, numVertices); delete[] polygon_connects; // cout << "numVertices: " << numVertices << endl // << "numPolygons: " << numPolygons << endl // << "pointArray: " << pointArray << endl // << "polygonCounts: " << polygonCounts << endl // << "polygonConnects: " << polygonConnects << endl // << "planeX: " << planeX << endl // << "planeY: " << planeY << endl // << "planeWidth: " << planeWidth << endl // << "planeHeight: " << planeHeight << endl; for (int i = 0; i < vPoints.length(); i++){ vPoints[i] = 1.0 - vPoints[i]; } MFnMesh mesh; object = mesh.create(numVertices, numPolygons, pointArray, polygonCounts, polygonConnects, uPoints, vPoints); mesh.assignUVs(polygonCounts, polygonConnects); return MS::kSuccess; }
// ------------------------------------------- // set the sampling function from the UI/command line. // Returns validity of the function bool AnimationHelper::setSamplingFunction ( const MFloatArray& function ) { std::vector<SamplingInterval> parsedFunction; // Order and parse the given floats as a function uint elementCount = function.length(); if ( elementCount > 1 && elementCount % 3 != 0 ) return false; if ( elementCount == 0 ) { generateSamplingFunction(); return true; } else if ( elementCount == 1 ) { SamplingInterval interval; interval.start = ( float ) animationStartTime().as ( MTime::kSeconds ); interval.end = ( float ) animationEndTime().as ( MTime::kSeconds ); interval.period = function[0]; parsedFunction.push_back ( interval ); } else { uint intervalCount = elementCount / 3; parsedFunction.resize ( intervalCount ); for ( uint i = 0; i < intervalCount; ++i ) { SamplingInterval& interval = parsedFunction[i]; interval.start = function[i * 3]; interval.end = function[i * 3 + 1]; interval.period = function[i * 3 + 2]; } } // Check for a valid sampling function uint parsedFunctionSize = ( uint ) parsedFunction.size(); for ( uint i = 0; i < parsedFunctionSize; ++i ) { SamplingInterval& interval = parsedFunction[i]; if ( interval.end <= interval.start ) return false; if ( interval.period > interval.end - interval.start ) return false; if ( i > 0 && parsedFunction[i - 1].end > interval.start ) return false; if ( interval.period <= 0.0f ) return false; } // Gather the sampling times mSamplingTimes.clear(); float previousTime = ( float ) animationStartTime().as ( MTime::kSeconds ); float previousPeriodTakenRatio = 1.0f; for ( std::vector<SamplingInterval>::iterator it = parsedFunction.begin(); it != parsedFunction.end(); ++it ) { SamplingInterval& interval = ( *it ); float time = interval.start; if ( time == previousTime ) { // Continuity in the sampling, calculate overlap start time time = time + ( 1.0f - previousPeriodTakenRatio ) * interval.period; } for ( ; time <= interval.end - interval.period + FLT_TOLERANCE; time += interval.period ) { mSamplingTimes.push_back ( time ); } mSamplingTimes.push_back ( time ); previousTime = interval.end; previousPeriodTakenRatio = ( interval.end - time ) / interval.period; } return true; }