void exportShadingInputs() { MObject proceduralNode = m_dagPath.node(); MPlug nullPlug; MIteratorType filter; MIntArray filterTypes; filterTypes.append( MFn::kShadingEngine ); filterTypes.append( MFn::kDisplacementShader ); filter.setFilterList( filterTypes ); MItDependencyGraph itDG( proceduralNode, nullPlug, filter, MItDependencyGraph::kUpstream ); while( !itDG.isDone() ) { MObject node = itDG.currentItem(); MFnDependencyNode fnNode( node ); MPlug plug; if( fnNode.typeName() == "displacementShader" ) { plug = fnNode.findPlug( "displacement" ); } else { plug = fnNode.findPlug( "dsm" ); } ExportNode( plug ); itDG.next(); } }
void skinClusterWeights::populateInfluenceIndexArray(MFnSkinCluster &skinClusterFn, MIntArray &influenceIndexArray) { MStatus status; MIntArray allIndexArray; MDagPathArray pathArray; skinClusterFn.influenceObjects(pathArray, &status); for (unsigned j = 0; j < pathArray.length(); j++) { allIndexArray.append(skinClusterFn.indexForInfluenceObject(pathArray[j])); } if (influenceArray.length() > 0) { // Add the influence indices for the influence objects specified in the cmd for (unsigned j = 0; j < influenceArray.length(); j++) { unsigned int index = skinClusterFn.indexForInfluenceObject(influenceArray[j], &status); for (unsigned k = 0; k < allIndexArray.length(); k++) { if ((int)index == allIndexArray[k]) { influenceIndexArray.append(k); } } } } else { // Add the influence indices for all the influence objects of the skinCluster for (unsigned j = 0; j < allIndexArray.length(); j++) { influenceIndexArray.append(j); } } }
MObject MG_poseReader::makePlane(const MVector& p1,const MVector& p2,const MVector& p3){ MFnMesh meshFn; MPoint p1p (p1); MPoint p2p (p2); MPoint p3p (p3); MPointArray pArray; pArray.append(p1p); pArray.append(p2p); pArray.append(p3p); MIntArray polyCount; polyCount.append(3); MIntArray polyConnect; polyConnect.append(0); polyConnect.append(1); polyConnect.append(2); MFnMeshData data; MObject polyData = data.create(); MStatus stat; meshFn.create(3,1,pArray,polyCount,polyConnect,polyData,&stat); return polyData; }
MIntArray GetLocalIndex( MIntArray & getVertices, MIntArray & getTriangle ) { MIntArray localIndex; unsigned gv, gt; assert ( getTriangle.length() == 3 ); // Should always deal with a triangle for ( gt = 0; gt < getTriangle.length(); gt++ ) { for ( gv = 0; gv < getVertices.length(); gv++ ) { if ( getTriangle[gt] == getVertices[gv] ) { localIndex.append( gv ); break; } } // if nothing was added, add default "no match" if ( localIndex.length() == gt ) localIndex.append( -1 ); } return localIndex; }
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; }
MStatus MVGMesh::unsetAllBlindData() const { MStatus status; // Get all vertices MItMeshVertex vIt(_dagpath, MObject::kNullObj, &status); vIt.updateSurface(); vIt.geomChanged(); MIntArray componentId; while(!vIt.isDone()) { const int index = vIt.index(&status); componentId.append(index); vIt.next(); } MVGEditCmd* cmd = new MVGEditCmd(); if(cmd) { cmd->clearBD(_dagpath, componentId); MArgList args; if(cmd->doIt(args)) cmd->finalize(); } delete cmd; return status; }
MStatus sweptEmitter::emitCountPerPoint ( const MPlug &plug, MDataBlock &block, int length, // length of emitCountPP MIntArray &emitCountPP // output: emitCount for each point ) // // Descriptions: // Compute emitCount for each point where new particles come from. // { MStatus status; int plugIndex = plug.logicalIndex( &status ); McheckErr(status, "ERROR in emitCountPerPoint: when plug.logicalIndex.\n"); // Get rate and delta time. // double rate = rateValue( block ); MTime dt = deltaTimeValue( plugIndex, block ); // Compute emitCount for each point. // double dblCount = rate * dt.as( MTime::kSeconds ); int intCount = (int)dblCount; for( int i = 0; i < length; i++ ) { emitCountPP.append( intCount ); } return( MS::kSuccess ); }
//--------------------------------------------------------------------------- void componentConverter::getConnectedFaces(MIntArray& edgeIDs, MIntArray& result ) //--------------------------------------------------------------------------- { MItMeshEdge edgeIter(mesh); MIntArray connectedFaces; result.clear(); unsigned int l = edgeIDs.length(); for(unsigned int i = 0; i < l; i++) { edgeIter.setIndex(edgeIDs[i],tmp); edgeIter.getConnectedFaces(connectedFaces); for(unsigned int x = 0; x < connectedFaces.length();x++) { result.append(connectedFaces[x]); } } }
void mesh::appendToMesh(MPointArray& points, MIntArray& faceCounts,MIntArray& faceConnects){ for(int i=0;i<gPoints.length();i++){ points.append(gPoints[i]); } for(int i=0;i<gFaceCounts.length();i++){ faceCounts.append(gFaceCounts[i]); } for(int i=0;i<gFaceConnects.length();i++){ faceConnects.append(gFaceConnects[i]); } if(gPoints.length()==0){ std::string s=std::to_string((long double)gPoints.length()); MGlobal::displayInfo(MString(s.c_str())); s=std::to_string((long double)gFaceCounts[0]); MGlobal::displayInfo(MString(s.c_str())); s=std::to_string((long double)gFaceConnects.length()); MGlobal::displayInfo(MString(s.c_str())); } }
void ParameterisedHolderModificationCmd::restoreClassParameterStates( const IECore::CompoundData *classes, IECore::Parameter *parameter, const std::string &parentParameterPath ) { std::string parameterPath = parentParameterPath; if( parentParameterPath.size() ) { parameterPath += "."; } parameterPath += parameter->name(); if( parameter->isInstanceOf( "ClassParameter" ) ) { const CompoundData *c = classes->member<const CompoundData>( parameterPath ); if( c ) { ClassParameterHandler::setClass( parameter, c->member<const IECore::StringData>( "className" )->readable().c_str(), c->member<const IECore::IntData>( "classVersion" )->readable(), c->member<const IECore::StringData>( "searchPathEnvVar" )->readable().c_str() ); } } else if( parameter->isInstanceOf( "ClassVectorParameter" ) ) { const CompoundData *c = classes->member<const CompoundData>( parameterPath ); if( c ) { IECore::ConstStringVectorDataPtr parameterNames = c->member<const IECore::StringVectorData>( "parameterNames" ); IECore::ConstStringVectorDataPtr classNames = c->member<const IECore::StringVectorData>( "classNames" ); IECore::ConstIntVectorDataPtr classVersions = c->member<const IECore::IntVectorData>( "classVersions" ); MStringArray mParameterNames; MStringArray mClassNames; MIntArray mClassVersions; int numClasses = parameterNames->readable().size(); for( int i=0; i<numClasses; i++ ) { mParameterNames.append( parameterNames->readable()[i].c_str() ); mClassNames.append( classNames->readable()[i].c_str() ); mClassVersions.append( classVersions->readable()[i] ); } ClassVectorParameterHandler::setClasses( parameter, mParameterNames, mClassNames, mClassVersions ); } } if( parameter->isInstanceOf( IECore::CompoundParameter::staticTypeId() ) ) { CompoundParameter *compoundParameter = static_cast<CompoundParameter *>( parameter ); const CompoundParameter::ParameterVector &childParameters = compoundParameter->orderedParameters(); for( CompoundParameter::ParameterVector::const_iterator it = childParameters.begin(); it!=childParameters.end(); it++ ) { restoreClassParameterStates( classes, it->get(), parameterPath ); } } }
void CXRayObjectExport::recFindTransformDAGNodes( MString& nodeName, MIntArray& transformNodeIndicesArray ) { // To handle Maya groups we traverse the hierarchy starting at // each objectNames[i] going towards the root collecting transform // nodes as we go. MStringArray result; MString cmdStr = "listRelatives -ap " + nodeName; MGlobal::executeCommand( cmdStr, result ); if( result.length() == 0 ) // nodeName must be at the root of the DAG. Stop recursing return; for( unsigned int j=0; j<result.length(); j++ ) { // check if the node result[i] is of type transform MStringArray result2; MGlobal::executeCommand( "nodeType " + result[j], result2 ); if( result2.length() == 1 && result2[0] == "transform" ) { // check if result[j] is already in result[j] bool found=false; unsigned int i; for( i=0; i<transformNodeNameArray.length(); i++) { if( transformNodeNameArray[i] == result[j] ) { found = true; break; } } if( !found ) { transformNodeIndicesArray.append(transformNodeNameArray.length()); transformNodeNameArray.append(result[j]); } else { transformNodeIndicesArray.append(i); } recFindTransformDAGNodes(result[j], transformNodeIndicesArray); } } }
static void addCube( float scale, MFloatVector pos, int index_offset, MFloatPointArray &points, MIntArray &faceCounts, MIntArray &faceConnects) { #define mkpoint(x, y, z) points.append((MFloatPoint(x, y, z) * scale) + pos) mkpoint( 0.5, 0.5, 0.5); mkpoint(-0.5, 0.5, 0.5); mkpoint(-0.5,-0.5, 0.5); mkpoint( 0.5,-0.5, 0.5); mkpoint( 0.5, 0.5,-0.5); mkpoint(-0.5, 0.5,-0.5); mkpoint(-0.5,-0.5,-0.5); mkpoint( 0.5,-0.5,-0.5); #undef mkpoint for (int i = 0; i < 6; i++) faceCounts.append(4); int face_connects[6 * 4] = { 0, 1, 2, 3, 7, 6, 5, 4, 3, 7, 4, 0, 2, 1, 5, 6, 0, 4, 5, 1, 2, 6, 7, 3 }; for (int i = 0; i < 6 * 4; i++) { faceConnects.append(face_connects[i] + index_offset); } }
void CylinderMesh::appendToMesh( MPointArray& points, MIntArray& faceCounts, MIntArray& faceConnects) { MPointArray cpoints; MVectorArray cnormals; transform(cpoints, cnormals); int startIndex = points.length(); // offset for indexes for (int i = 0; i < cpoints.length(); i++) { points.append(cpoints[i]); } for (int i = 0; i < gFaceCounts.length(); i++) { faceCounts.append(gFaceCounts[i]); } for (int i = 0; i < gFaceConnects.length(); i++) { faceConnects.append(gFaceConnects[i]+startIndex); } }
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); }
//----------------------------------------------------------------------------------------- LPCSTR CXRayObjectExport::getMaterialName(MDagPath & mdagPath, int cid, int objectIdx) { MStatus stat; int i, length; MIntArray * currentMaterials = new MIntArray(); MStringArray mArray; for ( i=0; i<numSets; i++ ) { if ( lookup(mdagPath,i,cid) ) { MFnSet fnSet( (*sets)[i] ); if ( MFnSet::kRenderableOnly == fnSet.restriction(&stat) ) { currentMaterials->append( i ); mArray.append( fnSet.name() ); } } } // Test for equivalent materials // bool materialsEqual = false; if ((lastMaterials != NULL) && (lastMaterials->length() == currentMaterials->length())){ materialsEqual = true; length = lastMaterials->length(); for (i=0; i<length; i++){ if ((*lastMaterials)[i]!=(*currentMaterials)[i]){ materialsEqual = false; break; } } } if (!materialsEqual){ if (lastMaterials!=NULL) xr_delete(lastMaterials); lastMaterials = currentMaterials; int mLength = mArray.length(); if (mLength==0) xrDebug::Fatal(DEBUG_INFO,"Object '%s' has polygon '%d' without material.",0,cid); if (mLength>1){ xrDebug::Fatal(DEBUG_INFO,"Object '%s' has polygon '%d' with more than one material.",0,cid); } }else{ xr_delete(currentMaterials); } return mArray[0].asChar(); }
MStatus splitUV::pruneUVs( MIntArray& validUVIndices ) // // Description: // // This method will remove any invalid UVIds from the component list and UVId array. // The benefit of this is to reduce the amount of extra processing that the node would // have to perform. It will result in less iterations through the mesh as there are // less UVs to search for. // { MStatus status; unsigned i; MIntArray validUVIds; for( i = 0; i < validUVIndices.length(); i++ ) { int uvIndex = validUVIndices[i]; validUVIds.append( fSelUVs[uvIndex] ); } // Replace the local int array of UVIds // fSelUVs.clear(); fSelUVs = validUVIds; // Build the list of valid components // MFnSingleIndexedComponent compFn; compFn.create( MFn::kMeshMapComponent, &status ); MCheckStatus( status, "compFn.create( MFn::kMeshMapComponent )" ); status = compFn.addElements( validUVIds ); MCheckStatus( status, "compFn.addElements( validUVIds )" ); MObject component = compFn.object(); // Replace the component list // MFnComponentListData compListFn; compListFn.create(); status = compListFn.add( component ); MCheckStatus( status, "compListFn.add( component )" ); fComponentList = compListFn.object(); return status; }
void StartChunck(){ int tempo; int temp = ::output.tellp(); posfichier.append(temp); info = " start position: "; tempo = posfichier.length()-1; info += tempo; info += " rec adress : "; info += temp; //MGlobal::displayInfo(info); write_int(1); // écriture d'une valeur quelconque }
//--------------------------------------------------------------------- void componentConverter::getContainedEdges( MIntArray& vtxIDs, MIntArray& result ) //--------------------------------------------------------------------- { // result.clear(); MFnMesh meshFn(mesh); MItMeshVertex vertIter(mesh); BPT_BA searchArray(meshFn.numEdges()); MIntArray conEdges; unsigned int l = vtxIDs.length(); int indexValue; for(unsigned i = 0;i < l;i++) { vertIter.setIndex(vtxIDs[i],tmp); vertIter.getConnectedEdges(conEdges); for(unsigned int x = 0; x < conEdges.length(); x++) { indexValue = conEdges[x]; if( searchArray[indexValue] ) { result.append(indexValue); } else searchArray.setBitTrue(indexValue); } } }
static bool _AssignMaterialFaceSet( const MObject& shadingEngine, const MDagPath& shapeDagPath, const VtIntArray& faceIndices) { MStatus status; // Create component object using single indexed // components, i.e. face indices. MFnSingleIndexedComponent compFn; MObject faceComp = compFn.create(MFn::kMeshPolygonComponent, &status); if (!status) { TF_RUNTIME_ERROR("Failed to create face component."); return false; } MIntArray mFaces; TF_FOR_ALL(fIdxIt, faceIndices) { mFaces.append(*fIdxIt); }
MStatus SelectRingToolCmd2::redoIt() { //MGlobal::displayInfo( "redoIt" ); MItMeshPolygon polyIter( selEdgeObject ); MItMeshEdge edgeIter( selEdgeObject, selEdgeComp ); //MFnSingleIndexedComponent si( selEdgeComp ); //MGlobal::displayInfo( MString("doing stuff on ") + selEdgeObject.fullPathName() + " " + si.element(0) ); MFnSingleIndexedComponent indexedCompFn; MObject newComponent; MSelectionList newSel; MIntArray edges; MIntArray faces; unsigned int i; const int initEdgeIndex = edgeIter.index(); int initFaceIndex; int prevIndex, lastIndex; int faceIndex, edgeIndex; int newFaceIndex, newEdgeIndex; int nInitEdgeVisits; MIntArray remainFaces; MIntArray remainEdges; if( selType == RING ) { nInitEdgeVisits = 0; // Push the face+edge combo on both sides // of the current edge onto the stack edgeIter.getConnectedFaces( faces ); if( faces.length() > 1 ) { remainFaces.append( faces[1] ); remainEdges.append( initEdgeIndex ); } initFaceIndex = faces[0]; remainFaces.append( initFaceIndex ); remainEdges.append( initEdgeIndex ); while( remainFaces.length() ) { // Pop the face and edge indices lastIndex = remainFaces.length() - 1; faceIndex = remainFaces[ lastIndex ]; edgeIndex = remainEdges[ lastIndex ]; remainFaces.remove( lastIndex ); remainEdges.remove( lastIndex ); // If the current edge the initial edge if( faceIndex == initFaceIndex && edgeIndex == initEdgeIndex ) { // Reached back to the initial edge, so the loop is closed if( ++nInitEdgeVisits == 2 ) break; } // Add edge to the new selection list if( selEdges ) { newComponent = indexedCompFn.create( MFn::kMeshEdgeComponent ); indexedCompFn.addElement( edgeIndex ); newSel.add( selEdgeObject, newComponent ); } // Add vertices to the new selection list if( selVertices ) { newComponent = indexedCompFn.create( MFn::kMeshVertComponent ); edgeIter.setIndex( edgeIndex, prevIndex ); indexedCompFn.addElement( edgeIter.index(0) ); indexedCompFn.addElement( edgeIter.index(1) ); newSel.add( selEdgeObject, newComponent ); } if( faceIndex != -1 ) // Not a boundary edge { // Add face to the new selection list if( selFaces ) { newComponent = indexedCompFn.create( MFn::kMeshPolygonComponent ); indexedCompFn.addElement( faceIndex ); newSel.add( selEdgeObject, newComponent ); } // Get edge opposite the current edge // newEdgeIndex = navigateFace( selEdgeObject, faceIndex, edgeIndex, OPPOSITE ); // Get the face on the other side of the opposite edge // edgeIter.setIndex( newEdgeIndex, prevIndex ); edgeIter.getConnectedFaces( faces ); newFaceIndex = -1; // Initialize to a boundary edge if( faces.length() > 1 ) newFaceIndex = (faceIndex == faces[0]) ? faces[1] : faces[0]; // Push face and edge onto list remainFaces.append( newFaceIndex ); remainEdges.append( newEdgeIndex ); } } } else // Ring { int reflEdgeIndex; int newReflEdgeIndex; int initReflEdgeIndex; MIntArray remainReflEdges; nInitEdgeVisits = 0; // Push the face+edge+reflect combo on both sides // of the current edge onto the stack //edgeIter.setIndex( initEdgeIndex, prevIndex ); edgeIter.getConnectedFaces( faces ); initFaceIndex = faces[0]; for( i=0; i < 2; i++ ) { remainFaces.append( initFaceIndex ); remainEdges.append( initEdgeIndex ); remainReflEdges.append( navigateFace( selEdgeObject, initFaceIndex, initEdgeIndex, (i == 0) ? PREVIOUS : NEXT ) ); } initReflEdgeIndex = remainReflEdges[1]; while( remainFaces.length() ) { // Pop the face, edge, and reflEdge indices lastIndex = remainFaces.length() - 1; faceIndex = remainFaces[ lastIndex ]; edgeIndex = remainEdges[ lastIndex ]; reflEdgeIndex = remainReflEdges[ lastIndex ]; remainFaces.remove( lastIndex ); remainEdges.remove( lastIndex ); remainReflEdges.remove( lastIndex ); //MGlobal::displayInfo( MString("Face: ") + faceIndex + " edge: " + edgeIndex + " reflEdgeIndex: " + reflEdgeIndex ); // If the current edge the initial edge if( faceIndex == initFaceIndex && edgeIndex == initEdgeIndex && reflEdgeIndex == initReflEdgeIndex ) { // Reached back to the initial edge, so the ring is closed if( ++nInitEdgeVisits == 2 ) break; } // Add edge to the new selection list if( selEdges ) { newComponent = indexedCompFn.create( MFn::kMeshEdgeComponent ); indexedCompFn.addElement( edgeIndex ); newSel.add( selEdgeObject, newComponent ); } // Add vertices to the new selection list if( selVertices ) { newComponent = indexedCompFn.create( MFn::kMeshVertComponent ); edgeIter.setIndex( edgeIndex, prevIndex ); indexedCompFn.addElement( edgeIter.index(0) ); indexedCompFn.addElement( edgeIter.index(1) ); newSel.add( selEdgeObject, newComponent ); } // Add face to the new selection list if( selFaces ) { newComponent = indexedCompFn.create( MFn::kMeshPolygonComponent ); indexedCompFn.addElement( faceIndex ); newSel.add( selEdgeObject, newComponent ); } // Get the face on opposite side of reflEdge edgeIter.setIndex( reflEdgeIndex, prevIndex ); edgeIter.getConnectedFaces( faces ); // Only if there are two faces can their be an opposite face if( faces.length() > 1 ) { newFaceIndex = (faceIndex == faces[0]) ? faces[1] : faces[0]; int edgePrev = navigateFace( selEdgeObject, newFaceIndex, reflEdgeIndex, PREVIOUS ); int edgeNext = navigateFace( selEdgeObject, newFaceIndex, reflEdgeIndex, NEXT ); // Determine which of the edges touches the original edge // edgeIter.setIndex( edgeIndex, prevIndex ); if( edgeIter.connectedToEdge( edgePrev ) ) { newEdgeIndex = edgePrev; newReflEdgeIndex = navigateFace( selEdgeObject, newFaceIndex, newEdgeIndex, PREVIOUS ); } else { newEdgeIndex = edgeNext; newReflEdgeIndex = navigateFace( selEdgeObject, newFaceIndex, newEdgeIndex, NEXT ); } // Push face, edge, and reflEdge onto list remainFaces.append( newFaceIndex ); remainEdges.append( newEdgeIndex ); remainReflEdges.append( newReflEdgeIndex ); } } } // Set the active selection to the one previous to edge loop selection MGlobal::setActiveSelectionList( prevSel, MGlobal::kReplaceList ); // Update this selection based on the list adjustment setting MGlobal::selectCommand( newSel, listAdjust ); return MS::kSuccess; }
MStatus meshOpFty::doIt() // // Description: // Performs the operation on the selected mesh and components // { MStatus status; unsigned int i, j; // Get access to the mesh's function set // MFnMesh meshFn(fMesh); // The division count argument is used in many of the operations // to execute the operation multiple subsequent times. For example, // with a division count of 2 in subdivide face, the given faces will be // divide once and then the resulting inner faces will be divided again. // int divisionCount = 2; MFloatVector translation; if (fOperationType == kExtrudeEdges || fOperationType == kExtrudeFaces || fOperationType == kDuplicateFaces || fOperationType == kExtractFaces) { // The translation vector is used for the extrude, extract and // duplicate operations to move the result to a new position. For // example, if you extrude an edge on a mesh without a subsequent // translation, the extruded edge will be on at the position of the // orignal edge and the created faces will have no area. // // Here, we provide a translation that is in the same direction as the // average normal of the given components. // MFn::Type componentType = getExpectedComponentType(fOperationType); MIntArray adjacentVertexList; switch (componentType) { case MFn::kMeshEdgeComponent: for (i = 0; i < fComponentIDs.length(); ++i) { int2 vertices; meshFn.getEdgeVertices(fComponentIDs[i], vertices); adjacentVertexList.append(vertices[0]); adjacentVertexList.append(vertices[1]); } break; case MFn::kMeshPolygonComponent: for (i = 0; i < fComponentIDs.length(); ++i) { MIntArray vertices; meshFn.getPolygonVertices(fComponentIDs[i], vertices); for (j = 0; j < vertices.length(); ++j) adjacentVertexList.append(vertices[j]); } break; default: break; } MVector averageNormal(0, 0, 0); for (i = 0; i < adjacentVertexList.length(); ++i) { MVector vertexNormal; meshFn.getVertexNormal(adjacentVertexList[i], vertexNormal, MSpace::kWorld); averageNormal += vertexNormal; } if (averageNormal.length() < 0.001) averageNormal = MVector(0.0, 1.0, 0.0); else averageNormal.normalize(); translation = averageNormal; } // When doing an extrude operation, there is a choice of extrude the // faces/edges individually or together. If extrudeTogether is true and // multiple adjacent components are selected, they will be extruded as if // it were one more complex component. // // The following variable sets that option. // bool extrudeTogether = true; // Execute the requested operation // switch (fOperationType) { case kSubdivideEdges: { status = meshFn.subdivideEdges(fComponentIDs, divisionCount); CHECK_STATUS(status); break; } case kSubdivideFaces: { status = meshFn.subdivideFaces(fComponentIDs, divisionCount); CHECK_STATUS(status); break; } case kExtrudeEdges: { status = meshFn.extrudeEdges(fComponentIDs, divisionCount, &translation, extrudeTogether); CHECK_STATUS(status); break; } case kExtrudeFaces: { status = meshFn.extrudeFaces(fComponentIDs, divisionCount, &translation, extrudeTogether); CHECK_STATUS(status); break; } case kCollapseEdges: { status = meshFn.collapseEdges(fComponentIDs); CHECK_STATUS(status); break; } case kCollapseFaces: { status = meshFn.collapseFaces(fComponentIDs); CHECK_STATUS(status); break; } case kDuplicateFaces: { status = meshFn.duplicateFaces(fComponentIDs, &translation); CHECK_STATUS(status); break; } case kExtractFaces: { status = meshFn.extractFaces(fComponentIDs, &translation); CHECK_STATUS(status); break; } case kSplitLightning: { status = doLightningSplit(meshFn); CHECK_STATUS(status); break; } default: status = MS::kFailure; break; } return status; }
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); }
bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECore::MeshPrimitive>( from ); assert( mesh ); if ( !mesh->arePrimitiveVariablesValid() ) { return false; } MFloatPointArray vertexArray; MIntArray polygonCounts; MIntArray polygonConnects; MFnMesh fnMesh; int numVertices = 0; IECore::PrimitiveVariableMap::const_iterator it = mesh->variables.find("P"); if ( it != mesh->variables.end() ) { /// \todo Employ some M*Array converters to simplify this IECore::ConstV3fVectorDataPtr p = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data); if (p) { numVertices = p->readable().size(); vertexArray.setLength( numVertices ); for (int i = 0; i < numVertices; i++) { vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3f>( p->readable()[i] ); } } else { IECore::ConstV3dVectorDataPtr p = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data); if (p) { numVertices = p->readable().size(); vertexArray.setLength( numVertices ); for (int i = 0; i < numVertices; i++) { vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3d>( p->readable()[i] ); } } else { // "P" is not convertible to an array of "points" return false; } } } IECore::ConstIntVectorDataPtr verticesPerFace = mesh->verticesPerFace(); assert( verticesPerFace ); int numPolygons = verticesPerFace->readable().size(); polygonCounts.setLength( numPolygons ); for (int i = 0; i < numPolygons; i++) { polygonCounts[i] = verticesPerFace->readable()[i]; } IECore::ConstIntVectorDataPtr vertexIds = mesh->vertexIds(); assert( vertexIds ); int numPolygonConnects = vertexIds->readable().size(); polygonConnects.setLength( numPolygonConnects ); for (int i = 0; i < numPolygonConnects; i++) { polygonConnects[i] = vertexIds->readable()[i]; } MObject mObj = fnMesh.create( numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, to, &s ); if (!s) { return false; } it = mesh->variables.find("N"); if ( it != mesh->variables.end() ) { if (it->second.interpolation == IECore::PrimitiveVariable::FaceVarying ) { /// \todo Employ some M*Array converters to simplify this MVectorArray vertexNormalsArray; IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data); if (n) { int numVertexNormals = n->readable().size(); vertexNormalsArray.setLength( numVertexNormals ); for (int i = 0; i < numVertexNormals; i++) { vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3f>( n->readable()[i] ); } } else { IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data); if (n) { int numVertexNormals = n->readable().size(); vertexNormalsArray.setLength( numVertexNormals ); for (int i = 0; i < numVertexNormals; i++) { vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3d>( n->readable()[i] ); } } else { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"N\" has unsupported type \"%s\"." ) % it->second.data->typeName() ); } } if ( vertexNormalsArray.length() ) { MStatus status; MItMeshPolygon itPolygon( mObj, &status ); if( status != MS::kSuccess ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to create mesh iterator" ); } unsigned v = 0; MIntArray vertexIds; MIntArray faceIds; for ( ; !itPolygon.isDone(); itPolygon.next() ) { for ( v=0; v < itPolygon.polygonVertexCount(); ++v ) { faceIds.append( itPolygon.index() ); vertexIds.append( itPolygon.vertexIndex( v ) ); } } if( !fnMesh.setFaceVertexNormals( vertexNormalsArray, faceIds, vertexIds ) ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Setting normals failed" ); } } } else { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "PrimitiveVariable \"N\" has unsupported interpolation (expected FaceVarying)." ); } } bool haveDefaultUVs = false; IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( "s" ); IECore::RefCountedPtr sDataRef = ( sIt == mesh->variables.end() ) ? 0 : static_cast<IECore::RefCountedPtr>( sIt->second.data ); /// Add named UV sets std::set< std::string > uvSets; for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { const std::string &sName = it->first; size_t suffixOffset = sName.rfind( "_s" ); if ( ( suffixOffset != std::string::npos) && ( suffixOffset == sName.length() - 2 ) ) { std::string uvSetNameStr = sName.substr( 0, suffixOffset ); if ( uvSetNameStr.size() ) { MString uvSetName = uvSetNameStr.c_str(); std::string tName = uvSetNameStr + "_t"; std::string stIdName = uvSetNameStr + "Indices"; addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName ); uvSets.insert( uvSetNameStr ); if ( sDataRef == static_cast<IECore::RefCountedPtr>( it->second.data ) ) { haveDefaultUVs = true; } } } } /// Add default UV set if it isn't just a reference to a named set if ( !haveDefaultUVs ) { addUVSet( fnMesh, polygonCounts, mesh, "s", "t", "stIndices" ); } // We do the search again, but looking for primvars ending "_t", so we can catch cases where either "UVSETNAME_s" or "UVSETNAME_t" is present, but not both, taking care // not to attempt adding any duplicate sets for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { const std::string &tName = it->first; size_t suffixOffset = tName.rfind( "_t" ); if ( ( suffixOffset != std::string::npos) && ( suffixOffset == tName.length() - 2 ) ) { std::string uvSetNameStr = tName.substr( 0, suffixOffset ); if ( uvSetNameStr.size() && uvSets.find( uvSetNameStr ) == uvSets.end() ) { MString uvSetName = uvSetNameStr.c_str(); std::string sName = uvSetNameStr + "_s"; std::string stIdName = uvSetNameStr + "Indices"; addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName ); uvSets.insert( uvSetNameStr ); } } } /// If we're making a mesh node (rather than a mesh data) then make sure it belongs /// to the default shading group and add the ieMeshInterpolation attribute. MObject oMesh = fnMesh.object(); if( oMesh.apiType()==MFn::kMesh ) { assignDefaultShadingGroup( oMesh ); setMeshInterpolationAttribute( oMesh, mesh->interpolation() ); } /// \todo Other primvars, e.g. vertex color ("Cs") return true; }
MStatus volumeLight::doIt( const MArgList& args ) { MStatus stat; double arc = 180.0f; double coneEndRadius = 0.0f; MFnVolumeLight::MLightDirection volumeLightDirection = MFnVolumeLight::kOutward; MFnVolumeLight::MLightShape lightShape = MFnVolumeLight::kConeVolume; bool emitAmbient = true; unsigned i; // Parse the arguments. for ( i = 0; i < args.length(); i++ ) { if ( MString( "-a" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { double tmp = args.asDouble( ++i, &stat ); if ( MS::kSuccess == stat ) arc = tmp; } else if ( MString( "-c" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { double tmp = args.asDouble( ++i, &stat ); if ( MS::kSuccess == stat ) coneEndRadius = tmp; } else if ( MString( "-e" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { bool tmp = args.asBool( ++i, &stat ); if ( MS::kSuccess == stat ) emitAmbient = tmp; } } MFnVolumeLight light; light.create( true, &stat); cout<<"What's up?"; if ( MS::kSuccess != stat ) { cout<<"Error creating light."<<endl; return stat; } stat = light.setArc ((float)arc); if ( MS::kSuccess != stat ) { cout<<"Error setting \"arc\" attribute."<<endl; return stat; } stat = light.setVolumeLightDirection (volumeLightDirection); if ( MS::kSuccess != stat ) { cout<<"Error setting \"volumeLightDirection\" attribute."<<endl; return stat; } stat = light.setConeEndRadius ((float)coneEndRadius); if ( MS::kSuccess != stat ) { cout<<"Error setting \"coneEndRadius\" attribute."<<endl; return stat; } stat = light.setEmitAmbient (emitAmbient); if ( MS::kSuccess != stat ) { cout<<"Error setting \"emitAmbient\" attribute."<<endl; return stat; } stat = light.setLightShape (lightShape); if ( MS::kSuccess != stat ) { cout<<"Error setting \"lightShape\" attribute."<<endl; return stat; } double arcGet = light.arc (&stat); if ( MS::kSuccess != stat || arcGet != arc) { cout<<"Error getting \"arc\" attribute."<<endl; return stat; } MFnVolumeLight::MLightDirection volumeLightDirectionGet = light.volumeLightDirection (&stat); if ( MS::kSuccess != stat || volumeLightDirectionGet != volumeLightDirection) { cout<<"Error getting \"volumeLightDirection\" attribute."<<endl; return stat; } double coneEndRadiusGet = light.coneEndRadius (&stat); if ( MS::kSuccess != stat || coneEndRadiusGet != coneEndRadius) { cout<<"Error getting \"coneEndRadius\" attribute."<<endl; return stat; } bool emitAmbientGet = light.emitAmbient (&stat); if ( MS::kSuccess != stat || emitAmbientGet != emitAmbient) { cout<<"Error getting \"emitAmbient\" attribute."<<endl; return stat; } MFnVolumeLight::MLightShape lightShapeGet = light.lightShape (&stat); if ( MS::kSuccess != stat || lightShapeGet != lightShape) { cout<<"Error getting \"lightShape\" attribute."<<endl; return stat; } // Get reference to the penumbra ramp. MRampAttribute ramp = light.penumbraRamp (&stat); if ( MS::kSuccess != stat ) { cout<<"Error getting \"penumbraRamp\" attribute."<<endl; return stat; } MFloatArray a, b; MIntArray c,d; // Get the entries in the ramp ramp.getEntries (d, a, b, c, &stat); if ( MS::kSuccess != stat ) { cout<<"Error getting entries from \"penumbraRamp\" attribute."<<endl; return stat; } // There should be 2 entries by default. if (d.length() != 2) { cout<<"Invalid number of entries in \"penumbraRamp\" attribute."<<endl; return stat; } MFloatArray a1, b1; MIntArray c1; // Prepare an array of entries to add. // In this case we are just adding 1 more entry // at position 0.5 with a curve value of 0.25 and a linear interpolation. a1.append (0.5f); b1.append (0.25f); c1.append (MRampAttribute::kLinear); // Add it to the curve ramp ramp.addEntries (a1, b1, c1, &stat); if ( MS::kSuccess != stat) { cout<<"Error adding entries to \"penumbraRamp\" attribute."<<endl; return stat; } // Get the entries to make sure that the above add actually worked. MFloatArray a2, b2; MIntArray c2,d2; ramp.getEntries (d2, a2, b2, c2, &stat); if ( MS::kSuccess != stat ) { cout<<"Error getting entries from \"penumbraRamp\" attribute."<<endl; return stat; } if ( a.length() + a1.length() != a2.length()) { cout<<"Invalid number of entries in \"penumbraRamp\" attribute."<<endl; return stat; } // Now try to interpolate the value at a point float newVal = -1; ramp.getValueAtPosition(.3f, newVal, &stat); if ( MS::kSuccess != stat ) { cout<<"Error interpolating value from \"penumbraRamp\" attribute."<<endl; return stat; } if ( !EQUAL(newVal, .15f)) { cout<<"Invalid interpolation in \"penumbraRamp\" expected .15 got "<<newVal <<" ."<<endl; } // Try to delete an entry in an incorrect manner. // This delete will work because there is an entry at 0, // However we should never do it this way, because the entries // array can become sparse, so trying to delete an entry without // checking whether an entry exists at that index can cause a failure. MIntArray entriesToDelete; entriesToDelete.append (0); ramp.deleteEntries (entriesToDelete, &stat); if ( MS::kSuccess != stat ) { cout<<"Error deleting entries from \"penumbraRamp\" attribute."<<endl; return stat; } // Check to see whether the above delete worked. // As mentioned earlier it did work, but we shouldn't do it this way. // To illustrate why we shouldn't do it this way, we'll try to delete // entry at index 0 ( this no longer exists) ramp.getEntries (d2, a2, b2, c2, &stat); if ( a2.length() != 2) { cout<<"Invalid number of entries in \"penumbraRamp\" attribute."<<endl; return stat; } // Trying to delete entry at 0. entriesToDelete.clear(); entriesToDelete.append (0); ramp.deleteEntries (entriesToDelete, &stat); // It will fail because no entry exists. if ( MS::kSuccess == stat) { cout<<"Error deleting entries from \"penumbraRamp\" attribute."<<endl; return stat; } if ( a2.length() != 2) { cout<<"Invalid number of entries in \"penumbraRamp\" attribute."<<endl; return stat; } // The proper way to delete is to retrieve the index by calling "getEntries" ramp.getEntries (d2, a2, b2, c2, &stat); entriesToDelete.clear(); entriesToDelete.append (d2[0]); // Delete the first logical entry in the entry array. ramp.deleteEntries (entriesToDelete, &stat); if ( MS::kSuccess != stat) { cout<<"Error deleting entries from \"penumbraRamp\" attribute."<<endl; return stat; } // There should be only 1 entry left. ramp.getEntries (d2, a2, b2, c2, &stat); if ( MS::kSuccess != stat) { cout<<"Error getting entries from \"penumbraRamp\" attribute."<<endl; return stat; } entriesToDelete.clear(); entriesToDelete.append (d2[0]); // Can't delete the last entry, should return failure. ramp.deleteEntries (entriesToDelete, &stat); if ( MS::kSuccess == stat) { cout<<"Error deleting entries from \"penumbraRamp\" attribute."<<endl; return stat; } ramp.setPositionAtIndex (0.0f, d2[0], &stat); if ( MS::kSuccess != stat) { printf("Error setting position at index: %d, of \"penumbraRamp\" attribute.\n", d2[0]); return stat; } ramp.setValueAtIndex (1.0f, d2[0], &stat); if ( MS::kSuccess != stat) { printf("Error setting value at index: %d, of \"penumbraRamp\" attribute.\n", d2[0]); return stat; } ramp.setInterpolationAtIndex (MRampAttribute::kNone, d2[0], &stat); if ( MS::kSuccess != stat) { printf("Error setting interpolation at index: %d, of \"penumbraRamp\" attribute.\n", d2[0]); return stat; } MRampAttribute ramp2 = light.colorRamp (&stat); if ( MS::kSuccess != stat) { cout<<"Error getting \"colorRamp\" attribute."<<endl; return stat; } MFloatArray a3; MColorArray b3; MIntArray c3,d3; // Get the entries in the ramp ramp2.getEntries (d3, a3, b3, c3, &stat); if ( MS::kSuccess != stat) { cout<<"Error getting entries from \"colorRamp\" attribute."<<endl; return stat; } // There should be 2 entries by default. if ( d3.length() != 2) { cout<<"Invalid number of entries in \"colorRamp\" attribute."<<endl; return stat; } MFloatArray a4; MColorArray b4; MIntArray c4; // Prepare an array of entries to add. // In this case we are just adding 1 more entry // at position 0.5 withe curve value of 0.5 and a linear interpolation. a4.append (0.5f); b4.append (MColor (0.0f, 0.0f, 0.75f)); c4.append (MRampAttribute::kLinear); // Add it to the curve ramp ramp2.addEntries (a4, b4, c4, &stat); if ( MS::kSuccess != stat) { cout<<"Error adding entries to \"colorRamp\" attribute."<<endl; return stat; } // Get the entries to make sure that the above add actually worked. MFloatArray a5; MColorArray b5; MIntArray c5,d5; ramp2.getEntries (d5, a5, b5, c5, &stat); if ( MS::kSuccess != stat) { cout<<"Error getting entries from \"colorRamp\" attribute."<<endl; return stat; } if ( a3.length() + a4.length() != a5.length()) { cout<<"Invalid number of entries in \"colorRamp\" attribute."<<endl; return stat; } // Now try to interpolate the color at a point MColor newCol(0.0, 0.0, 0.0); ramp2.getColorAtPosition(.3f, newCol, &stat); if ( MS::kSuccess != stat ) { cout<<"Error interpolating color from \"penumbraRamp\" attribute."<<endl; return stat; } if ( !EQUAL(newCol[2], .45)) { cout<<"Invalid color interpolation in \"colorRamp\" expected .45 got "<<newCol[2]<<endl; } MColor clr (0.5, 0.5, 0.0); ramp2.setColorAtIndex (clr, d5[0], &stat); if ( MS::kSuccess != stat) { cout<<"Error setting color at index: "<<d5[0] <<", of \"colorRamp\" attribute."<<endl; return stat; } ramp2.setInterpolationAtIndex (MRampAttribute::kSpline, d5[1], &stat); if ( MS::kSuccess != stat) { cout<<"Error setting interpolation at index: "<<d5[1] <<", of \"colorRamp\" attribute."<<endl; return stat; } return stat; }
MStatus QueryF3d::doIt(const MArgList &argList) { MStatus stat; MSyntax syntax = newSyntax(); MArgParser args(syntax, argList); char msg[4096]; if (!args.isFlagSet("-file")) { MGlobal::displayError("queryF3d: missing -f/-file flag"); return MS::kFailure; } bool verbose = args.isFlagSet("-verbose"); MString sarg; stat = args.getFlagArgument("-file", 0, sarg); if (stat != MS::kSuccess) { stat.perror("queryF3d"); return stat; } std::string pat = sarg.asChar(); ToPrintfPattern(pat); if (verbose) { MGlobal::displayInfo("queryF3d: File pattern \"" + sarg + "\" -> \"" + MString(pat.c_str()) + "\""); } std::vector<std::string> files; int startFrame = -1; int endFrame = -1; if (GetFileList(pat, files, &startFrame, &endFrame) == 0) { MGlobal::displayError("queryF3d: No file matching " + sarg); return MS::kFailure; } if (verbose) { MGlobal::displayInfo("queryF3d: Found file(s)"); for (size_t i=0; i<files.size(); ++i) { MGlobal::displayInfo(" " + MString(files[i].c_str())); } } if (args.isFlagSet("-range")) { MIntArray res; res.append(startFrame); res.append(endFrame); setResult(res); return MS::kSuccess; } else { Field3D::Field3DInputFile f3d; if (f3d.open(files[0])) { if (args.isFlagSet("-partitions")) { MStringArray rv; std::vector<std::string> names; f3d.getPartitionNames(names); if (verbose) { sprintf(msg, "queryF3d: Found %lu partition(s)", names.size()); MGlobal::displayInfo(msg); } for (size_t i=0; i<names.size(); ++i) { rv.append(names[i].c_str()); } setResult(rv); return MS::kSuccess; } else if (args.isFlagSet("-layers")) { if (!args.isFlagSet("-partition")) { MGlobal::displayError("queryF3d: Please specify the partition with -p/-partition flag"); return MS::kFailure; } stat = args.getFlagArgument("-partition", 0, sarg); if (stat != MS::kSuccess) { stat.perror("queryF3d"); return stat; } MStringArray rv; std::string partition = sarg.asChar(); std::vector<std::string> names; bool scalar = args.isFlagSet("-scalar"); bool vector = args.isFlagSet("-vector"); if (!scalar && !vector) { // neither -scalar nor -vector flag were set, output both scalar = true; vector = true; } if (scalar) { f3d.getScalarLayerNames(names, partition); for (size_t i=0; i<names.size(); ++i) { rv.append(names[i].c_str()); } } if (vector) { names.clear(); f3d.getVectorLayerNames(names, partition); for (size_t i=0; i<names.size(); ++i) { rv.append(names[i].c_str()); } } setResult(rv); return MS::kSuccess; } else if (args.isFlagSet("-resolution")) { if (!args.isFlagSet("-partition")) { MGlobal::displayError("queryF3d: Please specify the partition with -p/-partition flag"); return MS::kFailure; } if (!args.isFlagSet("-layer")) { MGlobal::displayError("queryF3d: Please specify the layer with -l/-layer flag"); return MS::kFailure; } stat = args.getFlagArgument("-partition", 0, sarg); if (stat != MS::kSuccess) { stat.perror("queryF3d"); return stat; } std::string partition = sarg.asChar(); stat = args.getFlagArgument("-layer", 0, sarg); if (stat != MS::kSuccess) { stat.perror("queryF3d"); return stat; } std::string layer = sarg.asChar(); if (verbose) { sprintf(msg, "queryF3d: Read resolution for %s.%s", partition.c_str(), layer.c_str()); MGlobal::displayInfo(msg); } MIntArray rv; // When reading proxy layers, the type doesn't actually matters Field3D::EmptyField<Field3D::half>::Vec fields = f3d.readProxyLayer<Field3D::half>(partition, layer, false); if (fields.size() == 0) { fields = f3d.readProxyLayer<Field3D::half>(partition, layer, true); if (verbose && fields.size() > 0) { MGlobal::displayInfo("(vector field)"); } } else if (verbose) { MGlobal::displayInfo("(scalar field)"); } if (fields.size() > 0) { Field3D::V3i res = fields[0]->dataResolution(); rv.append(res.x); rv.append(res.y); rv.append(res.z); setResult(rv); return MS::kSuccess; } MGlobal::displayWarning("queryF3d: Unsupported field type"); return MS::kFailure; } else { MGlobal::displayInfo("queryF3d: Nothing to query"); return MS::kFailure; } } else { MGlobal::displayError("queryF3d: Could not open file \"" + MString(files[0].c_str()) + "\""); return MS::kFailure; } } }
void OutputTextures(MSelectionList selected){ MString temp; MString affich; int MatExists=0; for(int i=0;i<selected.length();i++){ MDagPath path; MObject obj; selected.getDagPath(i,path); obj=path.child(0); MFnMesh fn(path); obj=fn.parent(0); path.getAPathTo(fn.parent(0)); MFnMesh fna(path); unsigned int instancenumbers; MObjectArray shaders; MIntArray indices; fna.getConnectedShaders(instancenumbers,shaders,indices); switch(shaders.length()) { // if no shader applied to the mesh instance case 0: { //***************Affich("pas de matériaux"); } break; // if all faces use the same material // if more than one material is used, write out the face indices the materials // are applied to. default: { //************************Affich("trouvé plusieurs matériaux"); //write_int(shaders.length()); // now write each material and the face indices that use them for(int j=0;j < shaders.length();++j) { for(int matest=0;matest<Matid.length();matest++){ //**************************Affich(Matid[matest].asChar()); //*****************************Affich(GetShaderName( shaders[j] ).asChar()); if(Matid[matest]== GetShaderName( shaders[j] )){ MatExists = 1; }//fin if matid }// fin for matest if(MatExists != 1){ //*****************************Affich("matériau absent de la liste, enregistrement"); Matid.append(GetShaderName( shaders[j] ).asChar()); nb_Tex_by_Brush.append(0); writeTexture(shaders[j],"color"); //Affich(temp); }else { //************************************* Affich("matériau existe dans la liste"); }// fin if matexists MatExists = 0; }//fin for j shaders }// fin case default break; }//fin switches }//fin for selected Matid.clear(); }// fin output textures
bool Outputtexture(MFnDependencyNode& fn,const char* name) { MPlug p; MString r = name; r += "R"; MString g = name; g += "G"; MString b = name; b += "B"; MString a = name; a += "A"; // get the color value MColor color; // get a plug to the attribute p = fn.findPlug(r); p.getValue(color.r); p = fn.findPlug(g.asChar()); p.getValue(color.g); p = fn.findPlug(b.asChar()); p.getValue(color.b); p = fn.findPlug(a.asChar()); p.getValue(color.a); p = fn.findPlug(name); // will hold the txture node name MString texname; // get plugs connected to colour attribute MPlugArray plugs; p.connectedTo(plugs,true,false); // see if any file textures are present for(int i=0;i!=plugs.length();++i) { // if file texture found if(plugs[i].node().apiType() == MFn::kFileTexture) { // bind a function set to it .... MFnDependencyNode fnDep(plugs[i].node()); // to get the node name texname = fnDep.name(); int TexExists=0; for(int i=0;i<Texid.length();i++) { if(texname==Texid[i]) TexExists=1; } if(TexExists==0){ // écrire la texture car absente Texid.append(texname); Affich(texname); //write_int(Matid.length());//id Brush //write_int(1);//textures per brush //::output << GetShaderName( shaders[j] ).asChar(); // get the attribute for the full texture path MPlug ftn = fnDep.findPlug("ftn"); // get the filename from the attribute MString filename; ftn.getValue(filename); // write the file name nb_Tex_by_Brush[Matid.length()-1]++;// une nouvelle texture dans la brush courante Texids_by_brush.append(Texid.length()-1); ::output << filename; ::output << char(0x00); //write flags, blend default 1, 2 write_int(1); write_int(2); // write position default O, O write_float(0); write_float(0); //write scale default 1, 1 write_float(1); write_float(1); //rotation in radian default= 0 write_float(0); //OutputColors(shaders[j],"color"); //EndChunck(); }else { nb_Tex_by_Brush[Matid.length()-1]=0; //Texids_by_brush.append(0); Texids_by_brush.append(0); } // stop looping //TexExists=0; } } return true; }
PXR_NAMESPACE_OPEN_SCOPE /* static */ bool PxrUsdMayaTranslatorMesh::Create( const UsdGeomMesh& mesh, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (!mesh) { return false; } const UsdPrim& prim = mesh.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (!PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<GfVec3f> normals; VtArray<int> faceVertexCounts; VtArray<int> faceVertexIndices; UsdAttribute fvc = mesh.GetFaceVertexCountsAttr(); if (fvc.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexCounts). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvc.Get(&faceVertexCounts, 0); } UsdAttribute fvi = mesh.GetFaceVertexIndicesAttr(); if (fvi.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexIndices). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvi.Get(&faceVertexIndices, 0); } // Sanity Checks. If the vertex arrays are empty, skip this mesh if (faceVertexCounts.size() == 0 || faceVertexIndices.size() == 0) { MGlobal::displayError( TfStringPrintf("FaceVertex arrays are empty [Count:%zu Indices:%zu] on Mesh <%s>. Skipping...", faceVertexCounts.size(), faceVertexIndices.size(), prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // Gather points and normals // If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); UsdTimeCode normalsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t pointsNumTimeSamples = 0; if (args.GetReadAnimData()) { PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetPointsAttr(), args, &pointsTimeSamples); pointsNumTimeSamples = pointsTimeSamples.size(); if (pointsNumTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } std::vector<double> normalsTimeSamples; PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetNormalsAttr(), args, &normalsTimeSamples); if (normalsTimeSamples.size()) { normalsTimeSample = normalsTimeSamples[0]; } } mesh.GetPointsAttr().Get(&points, pointsTimeSample); mesh.GetNormalsAttr().Get(&normals, normalsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on Mesh <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } MIntArray polygonCounts( faceVertexCounts.cdata(), faceVertexCounts.size() ); MIntArray polygonConnects( faceVertexIndices.cdata(), faceVertexIndices.size() ); // == Create Mesh Shape Node MFnMesh meshFn; MObject meshObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } // Since we are "decollapsing", we will create a xform and a shape node for each USD prim std::string usdPrimName(prim.GetName().GetText()); std::string shapeName(usdPrimName); shapeName += "Shape"; // Set mesh name and register meshFn.setName(MString(shapeName.c_str()), false, &status); if (context) { std::string usdPrimPath(prim.GetPath().GetText()); std::string shapePath(usdPrimPath); shapePath += "/"; shapePath += shapeName; context->RegisterNewMayaNode( shapePath, meshObj ); // used for undo/redo } // If a material is bound, create (or reuse if already present) and assign it // If no binding is present, assign the mesh to the default shader const TfToken& shadingMode = args.GetShadingMode(); PxrUsdMayaTranslatorMaterial::AssignMaterial(shadingMode, mesh, meshObj, context); // Mesh is a shape, so read Gprim properties PxrUsdMayaTranslatorGprim::Read(mesh, meshObj, context); // Set normals if supplied MIntArray normalsFaceIds; if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { for (size_t i=0; i < polygonCounts.length(); i++) { for (int j=0; j < polygonCounts[i]; j++) { normalsFaceIds.append(i); } } if (normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } } // Determine if PolyMesh or SubdivMesh TfToken subdScheme = PxrUsdMayaMeshUtil::setSubdivScheme(mesh, meshFn, args.GetDefaultMeshScheme()); // If we are dealing with polys, check if there are normals // If we are dealing with SubdivMesh, read additional attributes and SubdivMesh properties if (subdScheme == UsdGeomTokens->none) { if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { PxrUsdMayaMeshUtil::setEmitNormals(mesh, meshFn, UsdGeomTokens->none); } } else { PxrUsdMayaMeshUtil::setSubdivInterpBoundary(mesh, meshFn, UsdGeomTokens->edgeAndCorner); PxrUsdMayaMeshUtil::setSubdivFVLinearInterpolation(mesh, meshFn); _AssignSubDivTagsToMesh(mesh, meshObj, meshFn); } // Set Holes VtArray<int> holeIndices; mesh.GetHoleIndicesAttr().Get(&holeIndices); // not animatable if ( holeIndices.size() != 0 ) { MUintArray mayaHoleIndices; mayaHoleIndices.setLength( holeIndices.size() ); for (size_t i=0; i < holeIndices.size(); i++) { mayaHoleIndices[i] = holeIndices[i]; } if (meshFn.setInvisibleFaces(mayaHoleIndices) == MS::kFailure) { MGlobal::displayError(TfStringPrintf("Unable to set Invisible Faces on <%s>", meshFn.fullPathName().asChar()).c_str()); } } // GETTING PRIMVARS std::vector<UsdGeomPrimvar> primvars = mesh.GetPrimvars(); TF_FOR_ALL(iter, primvars) { const UsdGeomPrimvar& primvar = *iter; const TfToken& name = primvar.GetBaseName(); const SdfValueTypeName& typeName = primvar.GetTypeName(); // If the primvar is called either displayColor or displayOpacity check // if it was really authored from the user. It may not have been // authored by the user, for example if it was generated by shader // values and not an authored colorset/entity. // If it was not really authored, we skip the primvar. if (name == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName || name == PxrUsdMayaMeshColorSetTokens->DisplayOpacityColorSetName) { if (!PxrUsdMayaRoundTripUtil::IsAttributeUserAuthored(primvar)) { continue; } } // XXX: Maya stores UVs in MFloatArrays and color set data in MColors // which store floats, so we currently only import primvars holding // float-typed arrays. Should we still consider other precisions // (double, half, ...) and/or numeric types (int)? if (typeName == SdfValueTypeNames->Float2Array) { // We assume that Float2Array primvars are UV sets. if (!_AssignUVSetPrimvarToMesh(primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for UV set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } else if (typeName == SdfValueTypeNames->FloatArray || typeName == SdfValueTypeNames->Float3Array || typeName == SdfValueTypeNames->Color3fArray || typeName == SdfValueTypeNames->Float4Array || typeName == SdfValueTypeNames->Color4fArray) { if (!_AssignColorSetPrimvarToMesh(mesh, primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for color set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } } // We only vizualize the colorset by default if it is "displayColor". MStringArray colorSetNames; if (meshFn.getColorSetNames(colorSetNames)==MS::kSuccess) { for (unsigned int i=0; i < colorSetNames.length(); i++) { const MString colorSetName = colorSetNames[i]; if (std::string(colorSetName.asChar()) == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetString()) { MFnMesh::MColorRepresentation csRep= meshFn.getColorRepresentation(colorSetName); if (csRep==MFnMesh::kRGB || csRep==MFnMesh::kRGBA) { // both of these are needed to show the colorset. MPlug plg=meshFn.findPlug("displayColors"); if ( !plg.isNull() ) { plg.setBool(true); } meshFn.setCurrentColorSetName(colorSetName); } break; } } } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // if (pointsNumTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject meshAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(meshObj); if (context) { context->RegisterNewMayaNode( blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { mesh.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create Mesh Shape Node MFnMesh meshFn; if ( meshAnimObj.isNull() ) { meshAnimObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created mesh by copying it and then setting the points meshAnimObj = meshFn.copy(meshAnimObj, mayaNodeTransformObj, &status); meshFn.setPoints(mayaPoints); } // Set normals if supplied // // NOTE: This normal information is not propagated through the blendShapes, only the controlPoints. // mesh.GetNormalsAttr().Get(&normals, pointsTimeSamples[ti]); if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices()) && normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } // Add as target and set as an intermediate object blendFn.addTarget(meshObj, ti, meshAnimObj, 1.0); meshFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( meshFn.fullPathName().asChar(), meshAnimObj ); // used for undo/redo } } // Animate the weights so that mesh0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(pointsNumTimeSamples); for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(pointsNumTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this mesh's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
void LuxRenderer::defineTriangleMesh(mtlu_MayaObject *obj, bool noObjectDef = false) { MObject meshObject = obj->mobject; MStatus stat = MStatus::kSuccess; MFnMesh meshFn(meshObject, &stat); CHECK_MSTATUS(stat); MItMeshPolygon faceIt(meshObject, &stat); CHECK_MSTATUS(stat); MPointArray points; meshFn.getPoints(points); MFloatVectorArray normals; meshFn.getNormals( normals, MSpace::kWorld ); MFloatArray uArray, vArray; meshFn.getUVs(uArray, vArray); logger.debug(MString("Translating mesh object ") + meshFn.name().asChar()); MString meshFullName = obj->fullNiceName; MIntArray trianglesPerFace, triVertices; meshFn.getTriangles(trianglesPerFace, triVertices); int numTriangles = 0; for( size_t i = 0; i < trianglesPerFace.length(); i++) numTriangles += trianglesPerFace[i]; // lux render does not have a per vertex per face normal definition, here we can use one normal and uv per vertex only // So I create the triangles with unique vertices, normals and uvs. Of course this way vertices etc. cannot be shared. int numPTFloats = numTriangles * 3 * 3; logger.debug(MString("Num Triangles: ") + numTriangles + " num tri floats " + numPTFloats); float *floatPointArray = new float[numPTFloats]; float *floatNormalArray = new float[numPTFloats]; float *floatUvArray = new float[numTriangles * 3 * 2]; logger.debug(MString("Allocated ") + numPTFloats + " floats for point and normals"); MIntArray triangelVtxIdListA; MFloatArray floatPointArrayA; MPointArray triPoints; MIntArray triVtxIds; MIntArray faceVtxIds; MIntArray faceNormalIds; int *triangelVtxIdList = new int[numTriangles * 3]; for( uint sgId = 0; sgId < obj->shadingGroups.length(); sgId++) { MString slotName = MString("slot_") + sgId; } int triCount = 0; int vtxCount = 0; for(faceIt.reset(); !faceIt.isDone(); faceIt.next()) { int faceId = faceIt.index(); int numTris; faceIt.numTriangles(numTris); faceIt.getVertices(faceVtxIds); MIntArray faceUVIndices; faceNormalIds.clear(); for( uint vtxId = 0; vtxId < faceVtxIds.length(); vtxId++) { faceNormalIds.append(faceIt.normalIndex(vtxId)); int uvIndex; faceIt.getUVIndex(vtxId, uvIndex); faceUVIndices.append(uvIndex); } int perFaceShadingGroup = 0; if( obj->perFaceAssignments.length() > 0) perFaceShadingGroup = obj->perFaceAssignments[faceId]; //logger.info(MString("Face ") + faceId + " will receive SG " + perFaceShadingGroup); 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]]; floatPointArray[vtxCount * 3] = points[vtxId0].x; floatPointArray[vtxCount * 3 + 1] = points[vtxId0].y; floatPointArray[vtxCount * 3 + 2] = points[vtxId0].z; floatNormalArray[vtxCount * 3] = normals[normalId0].x; floatNormalArray[vtxCount * 3 + 1] = normals[normalId0].y; floatNormalArray[vtxCount * 3 + 2] = normals[normalId0].z; floatUvArray[vtxCount * 2] = uArray[uvId0]; floatUvArray[vtxCount * 2 + 1] = vArray[uvId0]; vtxCount++; floatPointArray[vtxCount * 3] = points[vtxId1].x; floatPointArray[vtxCount * 3 + 1] = points[vtxId1].y; floatPointArray[vtxCount * 3 + 2] = points[vtxId1].z; floatNormalArray[vtxCount * 3] = normals[normalId1].x; floatNormalArray[vtxCount * 3 + 1] = normals[normalId1].y; floatNormalArray[vtxCount * 3 + 2] = normals[normalId1].z; floatUvArray[vtxCount * 2] = uArray[uvId1]; floatUvArray[vtxCount * 2 + 1] = vArray[uvId1]; vtxCount++; floatPointArray[vtxCount * 3] = points[vtxId2].x; floatPointArray[vtxCount * 3 + 1] = points[vtxId2].y; floatPointArray[vtxCount * 3 + 2] = points[vtxId2].z; floatNormalArray[vtxCount * 3] = normals[normalId2].x; floatNormalArray[vtxCount * 3 + 1] = normals[normalId2].y; floatNormalArray[vtxCount * 3 + 2] = normals[normalId2].z; floatUvArray[vtxCount * 2] = uArray[uvId2]; floatUvArray[vtxCount * 2 + 1] = vArray[uvId2]; vtxCount++; //logger.debug(MString("Vertex count: ") + vtxCount + " maxId " + ((vtxCount - 1) * 3 + 2) + " ptArrayLen " + (numTriangles * 3 * 3)); triangelVtxIdList[triCount * 3] = triCount * 3; triangelVtxIdList[triCount * 3 + 1] = triCount * 3 + 1; triangelVtxIdList[triCount * 3 + 2] = triCount * 3 + 2; triCount++; } } //generatetangents bool Generate tangent space using miktspace, useful if mesh has a normal map that was also baked using miktspace (such as blender or xnormal) false //subdivscheme string Subdivision algorithm, options are "loop" and "microdisplacement" "loop" //displacementmap string Name of the texture used for the displacement. Subdivscheme parameter must always be provided, as load-time displacement is handled by the loop-subdivision code. none - optional. (loop subdiv can be used without displacement, microdisplacement will not affect the mesh without a displacement map specified) //dmscale float Scale of the displacement (for an LDR map, this is the maximum height of the displacement in meter) 0.1 //dmoffset float Offset of the displacement. 0 //dmnormalsmooth bool Smoothing of the normals of the subdivided faces. Only valid for loop subdivision. true //dmnormalsplit bool Force the mesh to split along breaks in the normal. If a mesh has no normals (flat-shaded) it will rip open on all edges. Only valid for loop subdivision. false //dmsharpboundary bool Try to preserve mesh boundaries during subdivision. Only valid for loop subdivision. false //nsubdivlevels integer Number of subdivision levels. This is only recursive for loop subdivision, microdisplacement will need much larger values (such as 50). 0 bool generatetangents = false; getBool(MString("mtlu_mesh_generatetangents"), meshFn, generatetangents); int subdivscheme = 0; const char *subdAlgos[] = {"loop", "microdisplacement"}; getInt(MString("mtlu_mesh_subAlgo"), meshFn, subdivscheme); const char *subdalgo = subdAlgos[subdivscheme]; float dmscale; getFloat(MString("mtlu_mesh_dmscale"), meshFn, dmscale); float dmoffset; getFloat(MString("mtlu_mesh_dmoffset"), meshFn, dmoffset); MString displacementmap; getString(MString("mtlu_mesh_displacementMap"), meshFn, displacementmap); const char *displacemap = displacementmap.asChar(); bool dmnormalsmooth = true; getBool(MString("mtlu_mesh_dmnormalsmooth"), meshFn, dmnormalsmooth); bool dmnormalsplit = false; getBool(MString("mtlu_mesh_dmnormalsplit"), meshFn, dmnormalsplit); bool dmsharpboundary = false; getBool(MString("mtlu_mesh_dmsharpboundary"), meshFn, dmsharpboundary); int nsubdivlevels = 0; getInt(MString("mtlu_mesh_subdivlevel"), meshFn, nsubdivlevels); // a displacment map needs its own texture defintion MString displacementTextureName = ""; if(displacementmap.length() > 0) { ParamSet dmParams = CreateParamSet(); dmParams->AddString("filename", &displacemap); displacementTextureName = meshFn.name() + "_displacementMap"; this->lux->texture(displacementTextureName.asChar(), "float", "imagemap", boost::get_pointer(dmParams)); } ParamSet triParams = CreateParamSet(); int numPointValues = numTriangles * 3; int numUvValues = numTriangles * 3 * 2; clock_t startTime = clock(); logger.info(MString("Adding mesh values to params.")); triParams->AddInt("indices", triangelVtxIdList, numTriangles * 3); triParams->AddPoint("P", floatPointArray, numPointValues); triParams->AddNormal("N", floatNormalArray, numPointValues); triParams->AddFloat("uv", floatUvArray, numUvValues); if( nsubdivlevels > 0) triParams->AddInt("nsubdivlevels", &nsubdivlevels, 1); triParams->AddBool("generatetangents", &generatetangents, 1); triParams->AddString("subdivscheme", &subdalgo , 1); if(displacementmap.length() > 0) { triParams->AddFloat("dmoffset", &dmoffset, 1); triParams->AddFloat("dmscale", &dmscale, 1); const char *dmft = displacementTextureName.asChar(); triParams->AddString("displacementmap", &dmft); } triParams->AddBool("dmnormalsmooth", &dmnormalsmooth, 1); triParams->AddBool("dmnormalsplit", &dmnormalsplit, 1); triParams->AddBool("dmsharpboundary", &dmsharpboundary, 1); clock_t pTime = clock(); if(!noObjectDef) this->lux->objectBegin(meshFullName.asChar()); this->lux->shape("trianglemesh", boost::get_pointer(triParams)); if(!noObjectDef) this->lux->objectEnd(); clock_t eTime = clock(); logger.info(MString("Timing: Parameters: ") + ((pTime - startTime)/CLOCKS_PER_SEC) + " objTime " + ((eTime - pTime)/CLOCKS_PER_SEC) + " all " + ((eTime - startTime)/CLOCKS_PER_SEC)); return; }
//---------------------------------------------------------------------------------------------------------------------- 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); }