MFloatPointArray ropeGenerator::createHalfRope( int pointsCount, float radius ) { MFloatPointArray points; MPoint baseVector( 1,0,0 ); baseVector = baseVector * radius; points.append( MFloatPoint( baseVector.x, baseVector.y, baseVector.z, 1.0 ) ); float fbaseAngle = 180.0 / float( pointsCount ); for (int d = 1; d < pointsCount; d++) { if (d == 1) { MAngle baseAngle((fbaseAngle * 0.25), MAngle::kDegrees ); MVector vVector( baseVector ); vVector = vVector.rotateBy( MVector::kYaxis, baseAngle.asRadians() ); points.append( MFloatPoint( vVector.x, vVector.y, vVector.z, 1.0 ) ); } MAngle baseAngle((fbaseAngle * float( d ) ), MAngle::kDegrees ); MVector vVector( baseVector ); vVector = vVector.rotateBy( MVector::kYaxis, baseAngle.asRadians() ); points.append( MFloatPoint( vVector.x, vVector.y, vVector.z, 1.0 ) ); if ( d == pointsCount - 1 ) { MAngle baseAngle((fbaseAngle * ( d + 0.75 )), MAngle::kDegrees ); MVector vVector( baseVector ); vVector = vVector.rotateBy( MVector::kYaxis, baseAngle.asRadians() ); points.append( MFloatPoint( vVector.x, vVector.y, vVector.z, 1.0 ) ); } } return points; }
MObject animCube::createMesh(const MTime& time, MObject& outData, MStatus& stat) { int numVertices, frame; float cubeSize; MFloatPointArray points; MFnMesh meshFS; // Scale the cube on the frame number, wrap every 10 frames. frame = (int)time.as( MTime::kFilm ); if (frame == 0) frame = 1; cubeSize = 0.5f * (float)( frame % 10); const int numFaces = 6; numVertices = 8; const int numFaceConnects = 24; MFloatPoint vtx_1( -cubeSize, -cubeSize, -cubeSize ); MFloatPoint vtx_2( cubeSize, -cubeSize, -cubeSize ); MFloatPoint vtx_3( cubeSize, -cubeSize, cubeSize ); MFloatPoint vtx_4( -cubeSize, -cubeSize, cubeSize ); MFloatPoint vtx_5( -cubeSize, cubeSize, -cubeSize ); MFloatPoint vtx_6( -cubeSize, cubeSize, cubeSize ); MFloatPoint vtx_7( cubeSize, cubeSize, cubeSize ); MFloatPoint vtx_8( cubeSize, cubeSize, -cubeSize ); points.append( vtx_1 ); points.append( vtx_2 ); points.append( vtx_3 ); points.append( vtx_4 ); points.append( vtx_5 ); points.append( vtx_6 ); points.append( vtx_7 ); points.append( vtx_8 ); // Set up an array containing the number of vertices // for each of the 6 cube faces (4 verticies per face) // int face_counts[numFaces] = { 4, 4, 4, 4, 4, 4 }; MIntArray faceCounts( face_counts, numFaces ); // Set up and array to assign vertices from points to each face // int face_connects[ numFaceConnects ] = { 0, 1, 2, 3, 4, 5, 6, 7, 3, 2, 6, 5, 0, 3, 5, 4, 0, 4, 7, 1, 1, 7, 6, 2 }; MIntArray faceConnects( face_connects, numFaceConnects ); MObject newMesh = meshFS.create(numVertices, numFaces, points, faceCounts, faceConnects, outData, &stat); return newMesh; }
MBoundingBox BasicLocator::boundingBox() const { MBoundingBox bbox; MFloatPointArray points; points.clear(); points.setSizeIncrement(4); points.append(-1.0, 0.0, 0.0); points.append(1.0, 0.0, 0.0); points.append(0.0, 0.0, 1.0); points.append(0.0, 0.0, -1.0); for (unsigned int i = 0; i < points.length(); i++) bbox.expand(points[i]); return bbox; }
bool kgLocator::getPoints( MFloatPointArray &pts ) { MFloatPoint pt; pt.x = -0.5f; pt.y = 0.0f; pt.z = 0.0f; pts.append( pt ); pt.x = 0.5f; pt.y = 0.0f; pt.z = 0.0f; pts.append( pt ); pt.x = 0.0f; pt.y = 0.0f; pt.z = -0.5f; pts.append( pt ); pt.x = 0.0f; pt.y = 0.0f; pt.z = 0.5f; pts.append( pt ); assert( pts.length() == 4 ); return true; }
MStatus metro_model_translator::create_shape( const m2033::mesh_ptr m ) { MFloatPointArray v; MVectorArray norm; MIntArray p; MIntArray idx; MFnTransform transform_fn; MObject transform_obj = transform_fn.create( MObject::kNullObj ); transform_fn.setName( m->get_name().c_str() ); m2033::mesh::vertices mv = m->get_vertices(); m2033::mesh::indices mi = m->get_indices(); m2033::mesh::texcoords mt = m->get_tex_coords(); m2033::mesh::normals mn = m->get_normals(); for( unsigned i = 0; i < mv.size(); i++ ) { v.append( -mv[i].x, mv[i].y, mv[i].z ); norm.append( MVector( -mn[i].x, mn[i].y, mn[i].z ) ); } for( unsigned i = 0; i < mi.size() / 3; i++ ) { idx.append( mi[i*3+2] ); idx.append( mi[i*3+1] ); idx.append( mi[i*3] ); p.append( 3 ); } MFloatArray u_values, v_values; for( unsigned i = 0; i < mt.size(); i++ ) { u_values.append( mt[i].x ); v_values.append( -mt[i].y ); } MFnMesh meshFn; MObject mesh = meshFn.create( v.length(), p.length(), v, p, idx, u_values, v_values, transform_obj ); MString name = m->get_name().c_str(); meshFn.setName( name + MString("_shape") ); MStatus s = meshFn.assignUVs( p, idx, 0 ); if( !s ) { return s; } s = meshFn.unlockVertexNormals( idx ); if( !s ) { return s; } meshFn.setVertexNormals( norm, idx ); MObject mat = create_material( m->get_texture_name(), &s ); if( !s ) { return s; } MFnSet mat_fn(mat); mat_fn.addMember(mesh); return MS::kSuccess; }
void ropeGenerator::createCriclePoints( int pointsCount, MMatrix bMatrix, MFloatPointArray &points, float radius ) { MPoint baseVector2( radius,0,0 ); baseVector2 = baseVector2 * bMatrix; points.append( MFloatPoint( baseVector2.x, baseVector2.y, baseVector2.z, 1.0 ) ); float baseAngle = 360.0f / float( pointsCount ); for (int d = 1; d < pointsCount; d++ ) { MVector vVector( radius,0,0 ); vVector = vVector.rotateBy( MVector::kYaxis, MAngle( baseAngle * float( d ),MAngle::kDegrees).asRadians() ); MPoint point( vVector.x, vVector.y, vVector.z ); point = point * bMatrix; points.append( MFloatPoint( point.x, point.y, point.z, 1.0 )); } }
MObject AniMesh::readFrame(const MTime& time,MObject& outData,MStatus& stat) { MFloatPointArray points; MFnMesh meshFS; int frame = (int)time.as( MTime::kFilm ); if (frame == 0) frame = 1; vector<size_t> face_v; vector<double> points_v; char cfilename[256]; sprintf(cfilename, "%s%d.vrml",import_prefix.c_str(),frame); //sprintf(cfilename, "%s%d.vrml",import_prefix.c_str(),0); string filename = string(cfilename); fstream fp; fp.open(filename,ios::in); if (fp) { ImportVrml2 (filename, face_v, points_v); }else{ sprintf(cfilename, "%s%d.vrml",import_prefix.c_str(),0); string filename = string(cfilename); ImportVrml2(filename,face_v,points_v); } size_t numVertices = points_v.size()/3; size_t numFaces = face_v.size()/3; for(vector<double>::const_iterator it = points_v.begin();it != points_v.end();it+=3) { MFloatPoint vtx(*it,*(it+1),*(it+2)); points.append(vtx); } vector<int> face_count; for(int i=0;i<numFaces;i++) { face_count.push_back(3); } MIntArray faceCounts(&face_count[0],numFaces); vector<int> face_connects; face_connects.resize(face_v.size()); for(int i=0;i<face_v.size();++i) { face_connects[i] = face_v[i]; } MIntArray faceConnects( &face_connects[0], face_connects.size() ); MObject newMesh=meshFS.create(numVertices, numFaces,points, faceCounts, faceConnects,outData,&stat); return newMesh; }
void ropeGenerator::createRopesRings( int ropesCount, MMatrix bMatrix, MFloatPointArray &points, int pointsCount, float ropeStrength, float radius ) { MAngle angle( (180.0/ ropesCount ), MAngle::kDegrees ); float distanceToMoveRope = cos( angle.asRadians() ); float singleRopeRadius = sin( angle.asRadians() ); float baseAngle = 360.0f / float( ropesCount ); for ( int d = 1; d < ropesCount + 1; d++) { MFloatPointArray ropePoints( createHalfRope( pointsCount, singleRopeRadius ) ); for ( int ropP = 0; ropP < ropePoints.length(); ropP++) { MFloatPoint ropPoint( ropePoints[ropP] ); MVector ropV( ropPoint.x, ropPoint.y, ropPoint.z * ropeStrength ); ropV = ropV + MVector( 0,0,-distanceToMoveRope ); ropV = ropV.rotateBy( MVector::kYaxis, MAngle( baseAngle * float( d ), MAngle::kDegrees).asRadians() ); MPoint ropFinalPoint( ropV * radius ); ropFinalPoint = ropFinalPoint * bMatrix; points.append( MFloatPoint( ropFinalPoint.x, ropFinalPoint.y, ropFinalPoint.z ) ); } } }
void MayaGeoAttribute::transferValueToMaya(MPlug &plug, MDataBlock &data){ coral::Geo *coralGeo = value(); const std::vector<Imath::V3f> &coralPoints = coralGeo->points(); // transfer points MFloatPointArray mayaPoints; for(int i = 0; i < coralPoints.size(); ++i){ const Imath::V3f *coralPoint = &coralPoints[i]; mayaPoints.append(MFloatPoint(coralPoint->x, coralPoint->y, coralPoint->z)); } // transfer faces MIntArray mayaFaceCount; MIntArray mayaFaceVertices; const std::vector<std::vector<int> > coralFaces = coralGeo->rawFaces(); for(int polyId = 0; polyId < coralFaces.size(); ++polyId){ const std::vector<int> *coralFace = &coralFaces[polyId]; int faceVertexCount = coralFace->size(); mayaFaceCount.append(faceVertexCount); for(int i = 0; i < faceVertexCount; ++i){ mayaFaceVertices.append(coralFace->at(i)); } } // create maya mesh MDataHandle dataHandle = data.outputValue(plug); MFnMeshData dataCreator; MObject newOutputData = dataCreator.create(); MFnMesh newMesh; newMesh.create(mayaPoints.length(), coralFaces.size(), mayaPoints, mayaFaceCount, mayaFaceVertices, newOutputData); dataHandle.set(newOutputData); }
MStatus meshOpFty::doLightningSplit(MFnMesh& meshFn) // // Description: // Performs the kSplitLightning operation on the selected mesh // and components. It may not split all the selected components. // { unsigned int i, j; // These are the input arrays to the split function. The following // algorithm fills them in with the arguments for a continuous // split that goes through some of the selected faces. // MIntArray placements; MIntArray edgeIDs; MFloatArray edgeFactors; MFloatPointArray internalPoints; // The following array is going to be used to determine which faces // have been split. Since the split function can only split faces // which are adjacent to the earlier face, we may not split // all the faces // bool* faceTouched = new bool[fComponentIDs.length()]; for (i = 0; i < fComponentIDs.length(); ++i) faceTouched[i] = false; // We need a starting point. For this example, the first face in // the component list is picked. Also get a polygon iterator // to this face. // MItMeshPolygon itPoly(fMesh); for (; !itPoly.isDone(); itPoly.next()) { if (fComponentIDs[0] == itPoly.index()) break; } if (itPoly.isDone()) { // Should never happen. // delete [] faceTouched; return MS::kFailure; } // In this example, edge0 is called the starting edge and // edge1 is called the destination edge. This algorithm will split // each face from the starting edge to the destination edge // while going through two inner points inside each face. // int edge0, edge1; MPoint innerVert0, innerVert1; int nextFaceIndex = 0; // We need a starting edge. For this example, the first edge in the // edge list is used. // MIntArray edgeList; itPoly.getEdges(edgeList); edge0 = edgeList[0]; bool done = false; while (!done) { // Set this face as touched so that we don't try to split it twice // faceTouched[nextFaceIndex] = true; // Get the current face's center. It is used later in the // algorithm to calculate inner vertices. // MPoint faceCenter = itPoly.center(); // Iterate through the connected faces to find an untouched, // selected face and get the ID of the shared edge. That face // will become the next face to be split. // MIntArray faceList; itPoly.getConnectedFaces(faceList); nextFaceIndex = -1; for (i = 0; i < fComponentIDs.length(); ++i) { for (j = 0; j < faceList.length(); ++j) { if (fComponentIDs[i] == faceList[j] && !faceTouched[i]) { nextFaceIndex = i; break; } } if (nextFaceIndex != -1) break; } if (nextFaceIndex == -1) { // There is no selected and untouched face adjacent to this // face, so this algorithm is done. Pick the first edge that // is not the starting edge as the destination edge. // done = true; edge1 = -1; for (i = 0; i < edgeList.length(); ++i) { if (edgeList[i] != edge0) { edge1 = edgeList[i]; break; } } if (edge1 == -1) { // This should not happen, since there should be more than // one edge for each face // delete [] faceTouched; return MS::kFailure; } } else { // The next step is to find out which edge is shared between // the two faces and use it as the destination edge. To do // that, we need to iterate through the faces and get the // next face's list of edges. // itPoly.reset(); for (; !itPoly.isDone(); itPoly.next()) { if (fComponentIDs[nextFaceIndex] == itPoly.index()) break; } if (itPoly.isDone()) { // Should never happen. // delete [] faceTouched; return MS::kFailure; } // Look for a common edge ID in the two faces edge lists // MIntArray nextFaceEdgeList; itPoly.getEdges(nextFaceEdgeList); edge1 = -1; for (i = 0; i < edgeList.length(); ++i) { for (j = 0; j < nextFaceEdgeList.length(); ++j) { if (edgeList[i] == nextFaceEdgeList[j]) { edge1 = edgeList[i]; break; } } if (edge1 != -1) break; } if (edge1 == -1) { // Should never happen. // delete [] faceTouched; return MS::kFailure; } // Save the edge list for the next iteration // edgeList = nextFaceEdgeList; } // Calculate the two inner points that the split will go through. // For this example, the midpoints between the center and the two // farthest vertices of the edges are used. // // Find the 3D positions of the edges' vertices // MPoint edge0vert0, edge0vert1, edge1vert0, edge1vert1; MItMeshEdge itEdge(fMesh, MObject::kNullObj ); for (; !itEdge.isDone(); itEdge.next()) { if (itEdge.index() == edge0) { edge0vert0 = itEdge.point(0); edge0vert1 = itEdge.point(1); } if (itEdge.index() == edge1) { edge1vert0 = itEdge.point(0); edge1vert1 = itEdge.point(1); } } // Figure out which are the farthest from each other // double distMax = edge0vert0.distanceTo(edge1vert0); MPoint max0, max1; max0 = edge0vert0; max1 = edge1vert0; double newDist = edge0vert1.distanceTo(edge1vert0); if (newDist > distMax) { max0 = edge0vert1; max1 = edge1vert0; distMax = newDist; } newDist = edge0vert0.distanceTo(edge1vert1); if (newDist > distMax) { max0 = edge0vert0; max1 = edge1vert1; distMax = newDist; } newDist = edge0vert1.distanceTo(edge1vert1); if (newDist > distMax) { max0 = edge0vert1; max1 = edge1vert1; } // Calculate the two inner points // innerVert0 = (faceCenter + max0) / 2.0; innerVert1 = (faceCenter + max1) / 2.0; // Add this split's information to the input arrays. If this is // the last split, also add the destination edge's split information. // placements.append((int) MFnMesh::kOnEdge); placements.append((int) MFnMesh::kInternalPoint); placements.append((int) MFnMesh::kInternalPoint); if (done) placements.append((int) MFnMesh::kOnEdge); edgeIDs.append(edge0); if (done) edgeIDs.append(edge1); edgeFactors.append(0.5f); if (done) edgeFactors.append(0.5f); MFloatPoint point1((float)innerVert0[0], (float)innerVert0[1], (float)innerVert0[2], (float)innerVert0[3]); MFloatPoint point2((float)innerVert1[0], (float)innerVert1[1], (float)innerVert1[2], (float)innerVert1[3]); internalPoints.append(point1); internalPoints.append(point2); // For the next iteration, the current destination // edge becomes the start edge. // edge0 = edge1; } // Release the dynamically-allocated memory and do the actual split // delete [] faceTouched; return meshFn.split(placements, edgeIDs, edgeFactors, internalPoints); }
//---------------------------------------------------------------------------------------------------------------------- void OceanNode::createGrid(int _resolution, double _time, double _choppiness, MObject& _outputData, MStatus &_status){ int numTris = (_resolution-1)*(_resolution-1)*2; MFloatPointArray vertices; MIntArray numFaceVertices; MIntArray faceVertices; int tris[numTris*3]; int width = 500; int depth = 500; // calculate the deltas for the x,z values of our point float wStep=(float)width/(float)_resolution; float dStep=(float)depth/(float)_resolution; // now we assume that the grid is centered at 0,0,0 so we make // it flow from -w/2 -d/2 float xPos=-((float)width/2.0); float zPos=-((float)depth/2.0); // now loop from top left to bottom right and generate points m_ocean->update(_time); float2* heights = m_ocean->getHeights(); float2* chopXArray = m_ocean->getChopX(); float2* chopZArray = m_ocean->getChopZ(); // Sourced form Jon Macey's NGL library for(int z=0; z<_resolution; z++){ for(int x=0; x<_resolution; x++){ // Divide the values we get out of the FFT by 50000 to get them in a suitable range float height = heights[z * _resolution + x].x/50000.0; float chopX = _choppiness * chopXArray[z * _resolution + x].x/50000.0; float chopZ= _choppiness * chopZArray[z * _resolution + x].x/50000.0; int sign = 1.0; if ((x+z) % 2 != 0){ sign = -1.0; } vertices.append((xPos + (chopX * sign)), height * sign, (zPos + (chopZ * sign))); // calculate the new position zPos+=dStep; } // now increment to next z row xPos+=wStep; // we need to re-set the xpos for new row zPos=-((float)depth/2.0); } // Array for num vertices in each face for (int i=0; i<numTris; i++){ numFaceVertices.append(3); } // Assign vertices to each face int fidx = 0; for (int i=0; i<(_resolution-1); i++){ for (int j=0; j<(_resolution-1); j++){ tris[fidx*3+0] = (i+1)*_resolution+j; tris[fidx*3+1] = i*_resolution+j+1; tris[fidx*3+2] = i*_resolution+j; fidx++; tris[fidx*3+0] = (i+1)*_resolution+j; tris[fidx*3+1] = (i+1)*_resolution+j+1; tris[fidx*3+2] = i*_resolution+j+1; fidx++; } } for (uint i=0; i<sizeof(tris)/sizeof(int); i++){ faceVertices.append(tris[i]); } MFnMesh grid; grid.create(vertices.length(), numTris, vertices, numFaceVertices, faceVertices, _outputData, &_status); }
MObject ClothSimMayaPlugin::createMesh(const MTime& time, MObject& outData, MStatus& stat) { double t = time.as(MTime::kSeconds); if (t <= 1.0 / 24 && m_prevTime > 1.0/24) { m_simMesh.reset(0); } int nx = 60; int ny = 60; if (!m_simMesh.get()) { Eigen::VectorXf v((nx+1) * (ny+1) * 3); Eigen::VectorXf x((nx + 1) * (ny + 1) * 3); Eigen::VectorXf uv((nx + 1) * (ny + 1) * 2); for (int i = 0; i <= nx; ++i) { for (int j = 0; j <= ny; ++j) { int base = i + (nx+1) * j; uv[2 * base + 0] = (float)i / nx - 0.5f; uv[2 * base + 1] = (float)j / ny - 0.5f; x[3 * base + 0] = uv[2 * base + 0]; x[3 * base + 1] = 0; x[3 * base + 2] = uv[2 * base + 1]; v[3 * base + 0] = v[3 * base + 1] = v[3 * base + 2] = 0; } } std::vector<int> triangleInds; for (int i = 0; i < nx; ++i) { for (int j = 0; j < ny; ++j) { int base = i + (nx + 1) * j; triangleInds.push_back(base + 0); triangleInds.push_back(base + 1); triangleInds.push_back(base + (nx + 1)); triangleInds.push_back(base + 1); triangleInds.push_back(base + (nx + 2)); triangleInds.push_back(base + (nx + 1)); } } m_simMesh.reset( new ClothMesh<float>( x, v, uv, triangleInds, 0.01f, 1000000.0f, 1000000.0f, 0.01f, 1000.0f, 1000.0f, 1.0f ) ); } std::vector<int> constraintIndices; std::vector< Eigen::Matrix3f > constraintMatrices; Eigen::VectorXf constraintVelocityDeltas(m_simMesh->x().size()); constraintVelocityDeltas.setConstant(0); for (int i = 0; i <= nx; ++i) { for (int j = 0; j <= ny; ++j) { int idx = i + (nx + 1) * j; float x = (float)i / nx - 0.5f; float y = (float)j / ny - 0.5f; if (x * x + y * y < 0.3 * 0.3) { constraintIndices.push_back(idx); constraintMatrices.push_back(Eigen::Matrix3f::Zero()); } } } if (t > m_prevTime) { ConstrainedCGSolver<float> solver( constraintIndices, constraintMatrices, constraintVelocityDeltas, 0.01f, 400 ); GravityField<float> g( m_simMesh->m(), Eigen::Vector3f( 0,-9.8f, 0 ) ); std::vector< ForceField<float>* > forceFields; forceFields.push_back( &g ); try { std::cerr << "advance" << std::endl; m_simMesh->advance(forceFields, float(t - m_prevTime)*0.5f, solver); m_simMesh->advance(forceFields, float(t - m_prevTime)*0.5f, solver); std::cerr << "done" << std::endl; } catch (const std::exception &e) { std::cerr << e.what() << std::endl; stat = MStatus::kFailure; return MObject(); } catch (...) { std::cerr << "unknown exception" << std::endl; stat = MStatus::kFailure; return MObject(); } } m_prevTime = t; MFloatPointArray points; for (int i = 0; i < m_simMesh->x().size(); i += 3) { MFloatPoint p(m_simMesh->x()[i], m_simMesh->x()[i + 1], m_simMesh->x()[i + 2]); points.append(p); } MFnMesh meshFS; MIntArray faceCounts((int)m_simMesh->triangleIndices().size()/3, 3); MIntArray faceConnects; for (unsigned i = 0; i < m_simMesh->triangleIndices().size(); ++i) { faceConnects.append(m_simMesh->triangleIndices()[i]); } MObject newMesh = meshFS.create((int)m_simMesh->x().size() / 3, (int)m_simMesh->triangleIndices().size() / 3, points, faceCounts, faceConnects, outData, &stat); return newMesh; }
// // Recursively traverse a mesh by processing each face, and the neighbouring faces along it's edges. // The initial invocation of this routine provides the basis for the new first vertex/edge // and faces. // // The result of this routine is an array of values that map the old CV indices to the new ones. Along // the a new list of reindexed CVs is built, along with a list of poly counts and connetions. These // can be used to build a new mesh with the reordering specfied by the seed face and vertices. // // // Inputs: // path : Path to the object being traversed // faceIdx : Current face being traversed // v0, v1 : Veretices that define the direction of travel along the face // faceTraversal : An array booleans to track which faces have been // : traversed, controls the recursion // origVertices : The vertices from the original mesh. The could be obtained // : from the path, but are passed in for efficiency // // Outputs: // cvMapping : Mapping of the existing vertices to their new indices // : the fist values in the final array will be the intial v0, v1 // cvMappingInverse : The inverse of the cvMapping // : the value of items v0 and v1 will be 0 and 1 respectively // newPolygonCounts : Vertex counts for each of the new faces // newPolygonConnects : Connections, specified in terms of new CV indices // newVertices : The orginal vertices resorted based on the reindexing // // MStatus meshMapUtils::traverseFace( MDagPath& path, int faceIdx, int v0, int v1, MIntArray& faceTraversal, MIntArray& cvMapping, MIntArray& cvMappingInverse, MIntArray& newPolygonCounts, MIntArray& newPolygonConnects, MFloatPointArray& origVertices, MFloatPointArray& newVertices ) { int vtxCnt = -1; int dir = 0; int dummy; // For setIndex calls MStatus stat = MStatus::kSuccess; MFnMesh theMesh( path, &stat ); MItMeshPolygon polyIt( path ); MItMeshEdge edgeIt( path ); if( stat != MStatus::kSuccess ) { MGlobal::displayError( " theMesh.getPoint failed"); return stat; } // // Skip over any faces already processed, this is not a failure // if( faceTraversal[faceIdx] ) { return MStatus::kSuccess; } // // get the vertex/edge information and sort it based on the user seed // MIntArray vtxOrig; MIntArray edgeOrig; polyIt.setIndex( faceIdx, dummy ); polyIt.getEdges( edgeOrig ); polyIt.getVertices( vtxOrig ); vtxCnt = vtxOrig.length(); // // the sorted V/E info // MIntArray vtxSorted( vtxCnt ); MIntArray edgeSorted( vtxCnt ); // // Build a new array ordered with v0, then v1, first figure out the // starting point, and direction // int v0Idx = -1; int i; for( i = 0; i < vtxCnt; i++ ) { if( vtxOrig[i] == v0 ) { // We've found v0, now find in what direction we need to travel to find v1 v0Idx = i; if( vtxOrig[IDX(i+1, vtxCnt)] == v1 ) { dir = 1; } else if( vtxOrig[IDX(i-1, vtxCnt)] == v1 ) { dir = -1; } break; } } if (dir == 0) { MGlobal::displayError("Selected vertices are not adjacent"); return MS::kFailure; } // Now sort the vertex/edge arrays for( i = 0; i < vtxCnt; i++ ) { vtxSorted[i] = vtxOrig[IDX( v0Idx + i * dir, vtxCnt )]; if( dir == 1 ) { edgeSorted[i] = edgeOrig[IDX( v0Idx + i * dir, vtxCnt )]; } else { edgeSorted[i] = edgeOrig[IDX( v0Idx - 1 + i * dir, vtxCnt )]; } } // Add any new CVs to the vertex array being constructed for ( i = 0; i < vtxCnt; i++ ) { MPoint pos; int index = vtxSorted[i]; if( cvMapping[index] == -1 ) { if( stat != MStatus::kSuccess ) { MGlobal::displayError( " theMesh.getPoint failed"); return stat; } // Added the new CV, and mark it as transferred newVertices.append( origVertices[index] ); // Store the mapping from the old CV indices to the new ones cvMapping[index] = newVertices.length()-1; cvMappingInverse[newVertices.length()-1] = index; } } // // Add the new face count // newPolygonCounts.append( vtxCnt ); // // Add the new polyConnects for ( i = 0; i < vtxCnt; i++ ) { newPolygonConnects.append( cvMapping[vtxSorted[i]] ); } // Mark this face as complete faceTraversal[faceIdx] = true; // // Now recurse over the edges of this face // for( i = 0; i < (int)edgeSorted.length(); i++ ) { int nextEdge = edgeSorted[i]; int2 nextEdgeVtx; stat = theMesh.getEdgeVertices(nextEdge, nextEdgeVtx ); // // Find the vertex, in the sorted array, that starts the next edge int baseIdx = -1; bool swap = false; int j; for( j = 0; j < (int)vtxSorted.length(); j++ ) { if( vtxSorted[j] == nextEdgeVtx[0] ) { baseIdx = j; break; } } assert( baseIdx != -1 ); // // Now look forward and backward in the vertex array to find the // edge's other point, this indicates the edges direction. This // is needed to guide the next recursion level, and keep the // normals pointed consistenly // if( vtxSorted[IDX(baseIdx+1, vtxCnt)] == nextEdgeVtx[1] ) { // Nothing } else if ( vtxSorted[IDX(baseIdx-1, vtxCnt)] == nextEdgeVtx[1] ) { swap = true; } MIntArray connectedFaces; edgeIt.setIndex( nextEdge, dummy ); edgeIt.getConnectedFaces( connectedFaces ); // A single face is simply the current one. Recurse over the others if( connectedFaces.length() > 1 ) { int nextFace; if( connectedFaces[0] == faceIdx ) { nextFace = connectedFaces[1]; } else { nextFace = connectedFaces[0]; } int nextVtx0 = -1; int nextVtx1 = -1; if ( !swap ) { nextVtx0 = nextEdgeVtx[1]; nextVtx1 = nextEdgeVtx[0]; } else { nextVtx0 = nextEdgeVtx[0]; nextVtx1 = nextEdgeVtx[1]; } stat = traverseFace( path, nextFace, nextVtx0, nextVtx1, faceTraversal, cvMapping, cvMappingInverse, newPolygonCounts, newPolygonConnects, origVertices, newVertices ); // Break out of edge loop on error if( stat != MStatus::kSuccess ) { break; } } } return stat; }
MObject blindDataMesh::createMesh(long seed, MObject& outData, MStatus& stat) { MFloatPointArray vertices; MIntArray faceDegrees; MIntArray faceVertices; int i, j; srand(seed); float planeSize = 20.0f; float planeOffset = planeSize / 2.0f; float planeDim = 0.5f; int numDivisions = (int) (planeSize / planeDim); // int numVertices = (numDivisions + 1) * (numDivisions + 1); // int numEdge = (2 * numDivisions) * (numDivisions + 1); int numFaces = numDivisions * numDivisions; // Set up an array containing the vertex positions for the plane. The // vertices are placed equi-distant on the X-Z plane to form a square // grid that has a side length of "planeSize". // // The Y-coordinate of each vertex is the average of the neighbors already // calculated, if there are any, with a small random offset added. Because // of the way the vertices are calculated, the whole plane will look like // it is streaked in a diagonal direction with mountains and depressions. // for (i = 0; i < (numDivisions + 1); ++i) { for (j = 0; j < (numDivisions + 1); ++j) { float height; if (i == 0 && j == 0) { height = ((rand() % 101) / 100.0f - 0.5f); } else if (i == 0) { float previousHeight = vertices[j - 1][1]; height = previousHeight + ((rand() % 101) / 100.0f - 0.5f); } else if (j == 0) { float previousHeight = vertices[(i-1)*(numDivisions + 1)][1]; height = previousHeight + ((rand() % 101) / 100.0f - 0.5f); } else { float previousHeight = vertices[(i-1)*(numDivisions + 1) + j][1]; float previousHeight2 = vertices[i*(numDivisions + 1) + j - 1][1]; height = (previousHeight + previousHeight2) / 2.0f + ((rand() % 101) / 100.0f - 0.5f); } MFloatPoint vtx( i * planeDim - planeOffset, height, j * planeDim - planeOffset ); vertices.append(vtx); } } // Set up an array containing the number of vertices // for each of the plane's faces // for (i = 0; i < numFaces; ++i) { faceDegrees.append(4); } // Set up an array to assign the vertices for each face // for (i = 0; i < numDivisions; ++i) { for (j = 0; j < numDivisions; ++j) { faceVertices.append(i*(numDivisions+1) + j); faceVertices.append(i*(numDivisions+1) + j + 1); faceVertices.append((i+1)*(numDivisions+1) + j + 1); faceVertices.append((i+1)*(numDivisions+1) + j); } } MFnMesh meshFn; MObject newMesh = meshFn.create(vertices.length(), numFaces, vertices, faceDegrees, faceVertices, outData, &stat); return newMesh; }
/* emits particles with color sampled from specified shading node/shading engine */ MStatus sampleParticles::doIt( const MArgList& args ) { unsigned int i; bool shadow = 0; bool reuse = 0; for ( i = 0; i < args.length(); i++ ) if ( args.asString(i) == MString("-shadow") || args.asString(i) == MString("-s") ) shadow = 1; else if ( args.asString(i) == MString("-reuse") || args.asString(i) == MString("-r") ) reuse = 1; else break; if ( args.length() - i < 5 ) { displayError( "Usage: sampleParticles [-shadow|-reuse] particleName <shadingEngine|shadingNode.plug> resX resY scale\n" " Example: sampleParticles -shadow particle1 phong1SG 64 64 10;\n" " Example: sampleParticles particle1 file1.outColor 128 128 5;\n" ); return MS::kFailure; } if ( reuse && !shadow ) // can only reuse if shadow is turned on reuse = 0; MString particleName = args.asString( i ); MString node = args.asString( i+1 ); int resX = args.asInt( i+2 ); int resY = args.asInt( i+3 ); double scale = args.asDouble( i+4 ); if ( scale <= 0.0 ) scale = 1.0; MFloatArray uCoord, vCoord; MFloatPointArray points; MFloatVectorArray normals, tanUs, tanVs; if ( resX <= 0 ) resX = 1; if ( resY <= 0 ) resY = 1; MString command( "emit -o " ); command += particleName; char tmp[2048]; float stepU = (float) (1.0 / resX); float stepV = (float) (1.0 / resY); // stuff sample data by iterating over grid // Y is set to arch along the X axis int x, y; for ( y = 0; y < resY; y++ ) for ( x = 0; x < resX; x++ ) { uCoord.append( stepU * x ); vCoord.append( stepV * y ); float curY = (float) (sin( stepU * (x) * M_PI )*2.0); MFloatPoint curPt( (float) (stepU * x * scale), curY, (float) (stepV * y * scale )); MFloatPoint uPt( (float) (stepU * (x+1) * scale), (float) (sin( stepU * (x+1) * M_PI )*2.0), (float) (stepV * y * scale )); MFloatPoint vPt( (float) (stepU * (x) * scale), curY, (float) (stepV * (y+1) * scale )); MFloatVector du, dv, n; du = uPt-curPt; dv = vPt-curPt; n = dv^du; // normal is based on dU x dV n = n.normal(); normals.append( n ); du.normal(); dv.normal(); tanUs.append( du ); tanVs.append( dv ); points.append( curPt ); } // get current camera's world matrix MDagPath cameraPath; M3dView::active3dView().getCamera( cameraPath ); MMatrix mat = cameraPath.inclusiveMatrix(); MFloatMatrix cameraMat( mat.matrix ); MFloatVectorArray colors, transps; if ( MS::kSuccess == MRenderUtil::sampleShadingNetwork( node, points.length(), shadow, reuse, cameraMat, &points, &uCoord, &vCoord, &normals, &points, &tanUs, &tanVs, NULL, // don't need filterSize colors, transps ) ) { fprintf( stderr, "%u points sampled...\n", points.length() ); for ( i = 0; i < uCoord.length(); i++ ) { sprintf( tmp, " -pos %g %g %g -at velocity -vv %g %g %g -at rgbPP -vv %g %g %g", points[i].x, points[i].y, points[i].z, normals[i].x, normals[i].y, normals[i].z, colors[i].x, colors[i].y, colors[i].z ); command += MString( tmp ); // execute emit command once every 512 samples if ( i % 512 == 0 ) { fprintf( stderr, "%u...\n", i ); MGlobal::executeCommand( command, false, false ); command = MString( "emit -o " ); command += particleName; } } if ( i % 512 ) MGlobal::executeCommand( command, true, true ); } else { displayError( node + MString(" is not a shading engine! Specify node.attr or shading group node." ) ); } return MS::kSuccess; }