MStatus ffdPlanar::getBoundingBox( MDataBlock& block, unsigned int multiIndex, MBoundingBox &boundingBoxOut ) { MStatus status = MS::kSuccess; MArrayDataHandle inputHandle = block.outputArrayValue( input ); inputHandle.jumpToElement( multiIndex ); MObject mesh = inputHandle.outputValue().child( inputGeom ).asMesh(); MBoundingBox boundingBox = MBoundingBox(); MFnMesh meshFn( mesh, &status ); MCheckErr( status, "Error getting mesh from mesh object\n" ); MPointArray pointArray = MPointArray(); meshFn.getPoints( pointArray, MSpace::kTransform ); for ( int i = 0; i < pointArray.length(); i++ ) { boundingBox.expand( pointArray[i] ); } boundingBoxOut = boundingBox; return status; }
// alembic by default sets meshes to be poly unless it's explicitly set to be // subdivision. UsdExport makes meshes catmullClark by default. Here, we // implement logic to get set the subdivision scheme so that it matches. static void _SetMeshesSubDivisionScheme( UsdStagePtr stage, const UsdMayaChaserRegistry::FactoryContext::DagToUsdMap& dagToUsd) { for (const auto& p: dagToUsd) { const MDagPath& dag = p.first; const SdfPath& usdPrimPath = p.second; if (!dag.isValid()) { continue; } MStatus status; MFnMesh meshFn(dag, &status); if (!status) { continue; } if (UsdGeomMesh usdMesh = UsdGeomMesh::Get(stage, usdPrimPath)) { MPlug plug = meshFn.findPlug("SubDivisionMesh"); bool isSubDivisionMesh = (!plug.isNull() && plug.asBool()); if (!isSubDivisionMesh) { usdMesh.GetSubdivisionSchemeAttr().Set(UsdGeomTokens->none); } } } }
void tm_polySlot::getMeshUVs() { MDagPath dagPath = getMeshNode(); MObject meshObject = dagPath.node(); MFnMesh meshFn( meshObject); MStringArray uvSetNames; MString currentUVSetName; MFloatArray *p_uArray = NULL; MFloatArray *p_vArray = NULL; MIntArray *p_uvCounts = NULL; MIntArray *p_uvIds = NULL; unsigned uvSetsCount = meshFn.numUVSets(); if(uvSetsCount > 0) { meshFn.getUVSetNames( uvSetNames); p_uArray = new MFloatArray[uvSetsCount]; p_vArray = new MFloatArray[uvSetsCount]; p_uvCounts = new MIntArray[uvSetsCount]; p_uvIds = new MIntArray[uvSetsCount]; meshFn.getCurrentUVSetName( currentUVSetName); for( unsigned i = 0; i < uvSetsCount; i++) { meshFn.getUVs( p_uArray[i], p_vArray[i], &uvSetNames[i]); meshFn.getAssignedUVs( p_uvCounts[i], p_uvIds[i], &uvSetNames[i]); } } #ifdef _DEBUG MString msg; msg = "Old uvSetsCount = " + uvSetsCount; msg += "UvSetNames = "; for(unsigned i=0;i<uvSetNames.length();i++) msg += uvSetNames[i] + ", "; MGlobal::displayInfo( msg); #endif }
void OsdPtexMeshData::initializeMesh() { if (!_hbrmesh) return; // create far mesh OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex> meshFactory(_hbrmesh, _level, _adaptive); _farmesh = meshFactory.Create(true /*ptex coords*/); delete _hbrmesh; _hbrmesh = NULL; int numTotalVertices = _farmesh->GetNumVertices(); // create context and vertex buffer clearComputeContextAndVertexBuffer(); if (_kernel == kCPU) { _cpuComputeContext = OpenSubdiv::OsdCpuComputeContext::Create(_farmesh); _cpuPositionBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices); if (not _adaptive) _cpuNormalBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices); #ifdef OPENSUBDIV_HAS_OPENMP } else if (_kernel == kOPENMP) { _cpuComputeContext = OpenSubdiv::OsdCpuComputeContext::Create(_farmesh); _cpuPositionBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices); if (not _adaptive) _cpuNormalBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices); #endif #ifdef OPENSUBDIV_HAS_CUDA } else if (_kernel == kCUDA) { _cudaComputeContext = OpenSubdiv::OsdCudaComputeContext::Create(_farmesh); _cudaPositionBuffer = OpenSubdiv::OsdCudaGLVertexBuffer::Create(3, numTotalVertices); if (not _adaptive) _cudaNormalBuffer = OpenSubdiv::OsdCudaGLVertexBuffer::Create(3, numTotalVertices); #endif #ifdef OPENSUBDIV_HAS_OPENCL } else if (_kernel == kCL) { _clComputeContext = OpenSubdiv::OsdCLComputeContext::Create(_farmesh, g_clContext); _clPositionBuffer = OpenSubdiv::OsdCLGLVertexBuffer::Create(3, numTotalVertices, g_clContext); if (not _adaptive) _clNormalBuffer = OpenSubdiv::OsdCLGLVertexBuffer::Create(3, numTotalVertices, g_clContext); #endif } _needsInitializeMesh = false; // get geometry from maya mesh MFnMesh meshFn(_meshDagPath); meshFn.getPoints(_pointArray); _needsUpdate = true; }
foundation::auto_release_ptr<renderer::MeshObject> createMesh(const MObject& mobject) { MStatus stat = MStatus::kSuccess; MFnMesh meshFn(mobject, &stat); CHECK_MSTATUS(stat); MPointArray points; MFloatVectorArray normals; MFloatArray uArray, vArray; MIntArray triPointIds, triNormalIds, triUvIds, triMatIds, perFaceAssignments; getMeshData(mobject, points, normals, uArray, vArray, triPointIds, triNormalIds, triUvIds, triMatIds, perFaceAssignments); foundation::auto_release_ptr<renderer::MeshObject> mesh( renderer::MeshObjectFactory::create( makeGoodString(meshFn.fullPathName()).asChar(), renderer::ParamArray())); for (unsigned int i = 0; i < points.length(); i++) mesh->push_vertex(mPointToGVector3(points[i])); for (unsigned int i = 0; i < normals.length(); i++) mesh->push_vertex_normal(mPointToGVector3(normals[i])); for (unsigned int i = 0; i < uArray.length(); i++) { mesh->push_tex_coords( renderer::GVector2( static_cast<float>(uArray[i]), static_cast<float>(vArray[i]))); } const unsigned int numTris = triPointIds.length() / 3; for (unsigned int i = 0; i < numTris; i++) { const int perFaceShadingGroup = triMatIds[i]; const int vtxId0 = triPointIds[i * 3 + 0]; const int vtxId1 = triPointIds[i * 3 + 1]; const int vtxId2 = triPointIds[i * 3 + 2]; const int normalId0 = triNormalIds[i * 3 + 0]; const int normalId1 = triNormalIds[i * 3 + 1]; const int normalId2 = triNormalIds[i * 3 + 2]; const int uvId0 = triUvIds[i * 3 + 0]; const int uvId1 = triUvIds[i * 3 + 1]; const int uvId2 = triUvIds[i * 3 + 2]; mesh->push_triangle( renderer::Triangle( vtxId0, vtxId1, vtxId2, normalId0, normalId1, normalId2, uvId0, uvId1, uvId2, perFaceShadingGroup)); } return mesh; }
//----------------------------------------------------------------------------- // Adds a color set to the input history of the passed mesh //----------------------------------------------------------------------------- MObject ValveMaya::AddColorSetToMesh( const MString &colorSetName, const MDagPath &mDagPath, MDagModifier &mDagModifier ) { if ( !mDagPath.hasFn( MFn::kMesh ) ) return MObject::kNullObj; MFnMesh meshFn( mDagPath ); MString uniqueColorSetName; { MStringArray colorSetNames; meshFn.getColorSetNames( colorSetNames ); const uint nColorSets( colorSetNames.length() ); for ( int i( 0 ); uniqueColorSetName.length() == 0; ++i ) { uniqueColorSetName = colorSetName; if ( i > 0 ) { uniqueColorSetName += i; } for ( uint j( 0U ); j != nColorSets; ++j ) { if ( uniqueColorSetName == colorSetNames[ j ] ) { uniqueColorSetName.clear(); break; } } } } // Create a 'createColorSet' node MObject ccsObj( mDagModifier.MDGModifier::createNode( "createColorSet" ) ); mDagModifier.doIt(); const MFnDependencyNode ccsFn( ccsObj ); MPlug csnP( ccsFn.findPlug( "colorSetName" ) ); csnP.setValue( uniqueColorSetName ); // Insert it in the history of the mesh MPlug inMeshP( meshFn.findPlug( "inMesh" ) ); MPlugArray mPlugArray; if ( inMeshP.connectedTo( mPlugArray, true, false ) && mPlugArray.length() ) { mDagModifier.disconnect( mPlugArray[ 0 ], inMeshP ); mDagModifier.connect( mPlugArray[ 0 ], ccsFn.findPlug( "inputGeometry" ) ); } mDagModifier.connect( ccsFn.findPlug( "outputGeometry" ), inMeshP ); mDagModifier.doIt(); return ccsObj; }
void OsdMeshData::initializeMesh() { if (!_hbrmesh) return; OpenSubdiv::OsdMeshBitset bits; bits.set(OpenSubdiv::MeshAdaptive, _adaptive!=0); bits.set(OpenSubdiv::MeshFVarData, true); if (_kernel == kCPU) { _mesh = new OpenSubdiv::OsdMesh<OpenSubdiv::OsdCpuGLVertexBuffer, OpenSubdiv::OsdCpuComputeController, OpenSubdiv::OsdGLDrawContext>( g_cpuComputeController, _hbrmesh, 3, _level, bits); #ifdef OPENSUBDIV_HAS_OPENMP } else if (_kernel == kOPENMP) { _mesh = new OpenSubdiv::OsdMesh<OpenSubdiv::OsdCpuGLVertexBuffer, OpenSubdiv::OsdOmpComputeController, OpenSubdiv::OsdGLDrawContext>( g_ompComputeController, _hbrmesh, 3, _level, bits); #endif #ifdef OPENSUBDIV_HAS_CUDA } else if(_kernel == kCUDA) { _mesh = new OpenSubdiv::OsdMesh<OpenSubdiv::OsdCudaGLVertexBuffer, OpenSubdiv::OsdCudaComputeController, OpenSubdiv::OsdGLDrawContext>( g_cudaComputeController, _hbrmesh, 3, _level, bits); #endif #ifdef OPENSUBDIV_HAS_OPENCL } else if(_kernel == kCL) { _mesh = new OpenSubdiv::OsdMesh<OpenSubdiv::OsdCLGLVertexBuffer, OpenSubdiv::OsdCLComputeController, OpenSubdiv::OsdGLDrawContext>( g_clComputeController, _hbrmesh, 3, _level, bits, g_clContext, g_clQueue); #endif } delete _hbrmesh; _hbrmesh = NULL; _needsInitializeMesh = false; // get geometry from maya mesh MFnMesh meshFn(_meshDagPath); meshFn.getPoints(_pointArray); _needsUpdate = true; }
void SubdivUserData::UpdatePoints(MObject mesh) { // update coarse vertex array MFnMesh meshFn(mesh); MStatus status; int nPoints = meshFn.numVertices(); const float *points = meshFn.getRawPoints(&status); // XXX: looking for other good way to detect change float total = 0; for(int i = 0; i < 3*nPoints; ++i) total += points[i]; if(_cachedTotal == total) return; _cachedTotal = total; MFloatVectorArray normals; meshFn.getVertexNormals(true, normals); if (nPoints != normals.length()) return; // XXX: error // Update vertex std::vector<float> vertex; vertex.resize(nPoints*6); for(int i = 0; i < nPoints; ++i){ vertex[i*6+0] = points[i*3+0]; vertex[i*6+1] = points[i*3+1]; vertex[i*6+2] = points[i*3+2]; vertex[i*6+3] = normals[i].x; vertex[i*6+4] = normals[i].y; vertex[i*6+5] = normals[i].z; } _vertexBuffer->UpdateData(&vertex.at(0), nPoints); /* XXX float *varying = new float[_osdmesh.GetNumVaryingElements()]; _osdmesh.BeginUpdateCoarseVertexVarying(); for(int i = 0; i < nPoints; ++i){ varying[0] = normals[i].x; varying[1] = normals[i].y; varying[2] = normals[i].z; _osdmesh.UpdateCoarseVertexVarying(i, varying); } _osdmesh.EndUpdateCoarseVertexVarying(); delete[] varying; */ // subdivide _osdmesh->Subdivide(_vertexBuffer, NULL); }
MStatus meshRemapTool::checkForHistory(const MDagPath& mesh) { MFnMesh meshFn(mesh); MPlug historyPlug = meshFn.findPlug("inMesh", true); if (historyPlug.isDestination()) { MGlobal::displayError("Destination mesh has history. Its geometry cannot be modified."); return MS::kInvalidParameter; } return MS::kSuccess; }
// if we have a mesh and it is a bifrost mesh it may contain velocity vertex data bool MayaObject::hasBifrostVelocityChannel() { MFnMesh meshFn(this->mobject); int numColorSets = meshFn.numColorSets(); MStringArray colorSetNames; meshFn.getColorSetNames(colorSetNames); for (uint i = 0; i < colorSetNames.length(); i++) { if (colorSetNames[i] == "bifrostVelocity") return true; } return false; }
MStatus updateTCCDataFty::doIt() // // Description: // Performs the actual updateTCCData operation on the given object and UVs // { MStatus status = MS::kSuccess; MFnMesh meshFn( fMesh ); remapMeshData(meshFn); return status; }
void SoftBodyNode::computeSoftBody(const MPlug &plug, MDataBlock &data) { // std::cout << "(SoftBodyNode::computeSoftBody) | "; MObject thisObject(thisMObject()); MPlug plgInputMesh(thisObject, inputMesh); MObject update; //force evaluation of the shape plgInputMesh.getValue(update); btAssert(plgInputMesh.isConnected()); MPlugArray connections; plgInputMesh.connectedTo(connections, true, false); // MFnDependencyNode fnNode(connections[0].node()); btAssert( connections.length() != 0); // std::cout << "(SoftBodyNode::computeSoftBody) Dependency node fn name: | " << fnNode.name() << std::endl; MFnMesh meshFn(connections[0].node()); MFnDagNode fnDagNode(thisObject); MFnTransform fnTransform(fnDagNode.parent(0)); MVector mtranslation = fnTransform.getTranslation(MSpace::kTransform); MQuaternion mrotation; fnTransform.getRotation(mrotation, MSpace::kObject); std::cout << "(SoftBodyNode::computeSoftBody) fnTranform: | " << fnTransform.name().asChar() << std::endl; std::cout << "(SoftBodyNode::computeSoftBody) fnTranform: | " << mtranslation.x << ", " << mtranslation.y << ", " << mtranslation.z << std::endl; solver_t::remove_soft_body(this->m_soft_body); std::vector<int> triVertIndices; std::vector<float> triVertCoords; createHelperMesh(meshFn, triVertIndices, triVertCoords, MSpace::kTransform); this->m_soft_body = solver_t::create_soft_body(triVertCoords, triVertIndices); solver_t::add_soft_body(this->m_soft_body, this->name().asChar()); // this->m_soft_body->set_transform(vec3f((float)mtranslation.x, (float)mtranslation.y, (float)mtranslation.z), // quatf((float)mrotation.w, (float)mrotation.x, (float)mrotation.y, (float)mrotation.z)); data.outputValue(ca_softBody).set(true); data.setClean(plug); }
void MayaGeoAttribute::transferValueFromMaya(MPlug &plug, MDataBlock &data){ MDataHandle dataHandle = data.inputValue(plug); MFnMesh meshFn(dataHandle.asMesh()); MFloatPointArray mayaPoints; meshFn.getPoints(mayaPoints); // collect points std::vector<Imath::V3f> coralPoints; for(int i = 0; i < mayaPoints.length(); ++i){ MFloatPoint* mayaPoint = &mayaPoints[i]; coralPoints.push_back(Imath::V3f(mayaPoint->x, mayaPoint->y, mayaPoint->z)); } // collect faces int numPolys = meshFn.numPolygons(); std::vector<std::vector<int> > coralFaces(numPolys); for(int polyId = 0; polyId < numPolys; ++polyId){ MIntArray mayaVertexList; meshFn.getPolygonVertices(polyId, mayaVertexList); int polyPoints = mayaVertexList.length(); std::vector<int> coralFace(polyPoints); for(int i = 0; i < polyPoints; ++i){ int pointId = mayaVertexList[i]; coralFace[i] = pointId; } coralFaces[polyId] = coralFace; } // create coral geo coral::Geo *coralGeo = outValue(); if(coralGeo->hasSameTopology(coralFaces)){ coralGeo->setPoints(coralPoints); } else{ coralGeo->build(coralPoints, coralFaces); } valueChanged(); }
void MayaObject::getMeshData(MPointArray& points, MFloatVectorArray& normals) { MStatus stat; MObject meshObject = this->mobject; MMeshSmoothOptions options; MFnMesh tmpMesh(this->mobject); MFnMeshData meshData; MObject dataObject; MObject smoothedObj; // create smooth mesh if needed if (tmpMesh.findPlug("displaySmoothMesh").asBool()) { stat = tmpMesh.getSmoothMeshDisplayOptions(options); if (stat) { if (!tmpMesh.findPlug("useSmoothPreviewForRender", false, &stat).asBool()) { //Logging::debug(MString("useSmoothPreviewForRender turned off")); int smoothLevel = tmpMesh.findPlug("renderSmoothLevel", false, &stat).asInt(); options.setDivisions(smoothLevel); } if (options.divisions() > 0) { dataObject = meshData.create(); smoothedObj = tmpMesh.generateSmoothMesh(dataObject, &options, &stat); if (stat) { meshObject = smoothedObj; } } } } MFnMesh meshFn(meshObject, &stat); if (!stat) { MString error = stat.errorString(); Logging::error(error); } meshFn.getPoints(points); meshFn.getNormals(normals, MSpace::kObject); }
//--------------------------------------------------------------------- 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); } } }
void tm_polySlot::setMeshUVs() { MStatus status( MStatus::kSuccess); MDagPath dagPath = getMeshNode(); MObject meshObject = dagPath.node(); MFnMesh meshFn( meshObject); #ifdef _DEBUG MString msg; uvSetsCount = meshFn.numUVSets(); if(uvSetsCount > 0) meshFn.getUVSetNames( uvSetNames); msg = "Old uvSetsCount = " + uvSetsCount; msg += "UvSetNames = "; for(unsigned i=0;i<uvSetNames.length();i++) msg += uvSetNames[i] + ", "; MGlobal::displayInfo( msg); #endif /* for( unsigned i = 0; i < uvSetNames.length(); i++) { status = meshFn.deleteUVSet( uvSetNames[i], &dgModifier); if(!status) MGlobal::displayError("Can't delete uvSet " + uvSetNames[i]); } */ // i = 0; for( unsigned i = 0; i < uvSetsCount; i++) { // status = meshFn.setCurrentUVSetName( uvSetNames[i]); // if(!status) MGlobal::displayError("Can't set current " + uvSetNames[i] + " uvSet."); // status = meshFn.deleteUVSet( uvSetNames[i]); // if(!status) MGlobal::displayError("Can't delete uvSet " + uvSetNames[i]); // meshFn.clearUVs( &uvSetNames[i]); // status = meshFn.createUVSet( uvSetNames[i]); // if(!status) MGlobal::displayError("Can't create uvSet " + uvSetNames[i]); status = meshFn.setUVs( p_uArray[i], p_vArray[i], &uvSetNames[i]); if(!status) MGlobal::displayError("Can't set uvSet " + uvSetNames[i]); status = meshFn.assignUVs( p_uvCounts[i], p_uvIds[i], &uvSetNames[i]); if(!status) MGlobal::displayError("Can't assign uvSet " + uvSetNames[i]); } }
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; }
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; }
void VMesh::save(const char* filename, int isStart) { MStatus status; MFnMesh meshFn(pgrow, &status ); MItMeshPolygon faceIter( pgrow, &status ); MItMeshVertex vertIter(pgrow, &status); int m_n_triangle=0, m_n_vertex=0; MIntArray m_vertex_id; MFloatArray facevarying_s, facevarying_t; MPointArray m_vertex_p; MVectorArray m_vertex_n, m_vertex_t; meshFn.getPoints(m_vertex_p, MSpace::kWorld); float auv[2]; faceIter.reset(); for( ; !faceIter.isDone(); faceIter.next() ) { MIntArray vexlist; faceIter.getVertices ( vexlist ); m_n_triangle += vexlist.length() - 2; for( unsigned int i=1; i < vexlist.length()-1; i++ ) { m_vertex_id.append(vexlist[0]); m_vertex_id.append(vexlist[i]); m_vertex_id.append(vexlist[i+1]); faceIter.getUV(0, auv); facevarying_s.append(auv[0]); facevarying_t.append(auv[1]); faceIter.getUV(i, auv); facevarying_s.append(auv[0]); facevarying_t.append(auv[1]); faceIter.getUV(i+1, auv); facevarying_s.append(auv[0]); facevarying_t.append(auv[1]); } } XYZ* pbinormal = new XYZ[meshFn.numVertices()]; XYZ* pv = new XYZ[meshFn.numVertices()]; float* pscale = new float[meshFn.numVertices()]; float* curlarray = new float[meshFn.numVertices()]; float* widtharray = new float[meshFn.numVertices()]; float* densityarray = new float[meshFn.numVertices()]; MVector tnor, tang, ttang, binormal, dir, hair_up, hair_v; MPoint tpos; MColor Cscale, Cerect, Crotate, Cstiff, Ccurl, Cwidth, Cdensity; float rot; MATRIX44F hair_space, hair_space_inv; MString setScale("fb_scale"); MString setErect("fb_erect"); MString setRotate("fb_rotate"); MString setStiff("fb_stiffness"); MString setCurl("fb_curl"); MString setWidth("fb_width"); MString setDensity("fb_density"); MIntArray conn_face; XYZ dP; vertIter.reset(); for( int i=0; !vertIter.isDone(); vertIter.next(), i++ ) { vertIter.getConnectedFaces(conn_face); vertIter.getNormal(tnor, MSpace::kWorld); tnor.normalize(); m_vertex_n.append(tnor); vertIter.getColor(Cscale, &setScale); vertIter.getColor(Cerect, &setErect); vertIter.getColor(Crotate, &setRotate); vertIter.getColor(Cstiff, &setStiff); vertIter.getColor(Ccurl, &setCurl); vertIter.getColor(Cwidth, &setWidth); vertIter.getColor(Cdensity, &setDensity); if(Cstiff.r < 0.1) Cstiff.r = 0.1; tang = MVector(0,0,0); for(int j=0; j<conn_face.length(); j++) { meshFn.getFaceVertexTangent (conn_face[j], i, ttang, MSpace::kWorld); ttang.normalize(); tang += ttang; } tang /= conn_face.length(); conn_face.clear(); tang.normalize(); tang = tnor^tang; tang.normalize(); binormal = tnor^tang; if(Crotate.r<0.5) { rot = (0.5 - Crotate.r)*2; tang = tang + (binormal-tang)*rot; tang.normalize(); binormal = tnor^tang; } else { rot = (Crotate.r-0.5)*2; tang = tang + (binormal*-1-tang)*rot; tang.normalize(); binormal = tnor^tang; } pbinormal[i] = XYZ(binormal.x, binormal.y, binormal.z); pscale[i] = Cscale.r * m_scale; dir = tang + (tnor - tang)*Cerect.r; dir.normalize(); m_vertex_t.append(dir); hair_up = dir^binormal; //pup[i] = XYZ(hair_up.x, hair_up.y, hair_up.z); hair_space.setIdentity(); hair_space.setOrientations(XYZ(binormal.x, binormal.y, binormal.z), XYZ(hair_up.x, hair_up.y, hair_up.z), XYZ(dir.x, dir.y, dir.z)); hair_space.setTranslation(XYZ(m_vertex_p[i].x, m_vertex_p[i].y, m_vertex_p[i].z)); hair_space_inv = hair_space; hair_space_inv.inverse(); hair_v = getVelocity(i); dP = XYZ(hair_v.x, hair_v.y, hair_v.z); hair_space_inv.transformAsNormal(dP); if(dP.y<0) dP.y = 0; dP *= m_wind/Cstiff.r; pv[i] = dP; curlarray[i] = Ccurl.r; widtharray[i] = Cwidth.r; densityarray[i] = Cdensity.r; } m_n_vertex = meshFn.numVertices(); FXMLTriangleMap fmap; fmap.beginMap(filename); // write vertex id string static_path(filename); zGlobal::cutByFirstDot(static_path); static_path.append(".hbs"); if(isStart == 1) { fmap.staticBegin(static_path.c_str(), m_n_triangle); int* id_list = new int[m_n_triangle*3]; for(int i=0; i<m_n_triangle*3; i++) id_list[i] = m_vertex_id[i]; fmap.addVertexId(m_n_triangle*3, id_list); delete[] id_list; float* sarray = new float[m_n_triangle*3]; float* tarray = new float[m_n_triangle*3]; for(int i=0; i<m_n_triangle*3; i++) { sarray[i] = facevarying_s[i]; tarray[i] = facevarying_t[i]; } fmap.addStaticFloatArray("root_s", m_n_triangle*3, sarray); fmap.addStaticFloatArray("root_t", m_n_triangle*3, tarray); delete[] sarray; delete[] tarray; XYZ* recpref = new XYZ[m_n_vertex]; for(int i=0; i<m_n_vertex; i++) recpref[i] = XYZ(m_vertex_p[i].x, m_vertex_p[i].y, m_vertex_p[i].z); fmap.addPref(m_n_vertex, recpref); delete[] recpref; fmap.addStaticFloatArray("scale", m_n_vertex, pscale); fmap.addStaticFloatArray("curl", m_n_vertex, curlarray); fmap.addStaticFloatArray("width", m_n_vertex, widtharray); fmap.addStaticFloatArray("density", m_n_vertex, densityarray); fmap.staticEnd(); } else { fmap.staticBeginNoWrite(static_path.c_str(), m_n_triangle); fmap.addVertexId(m_n_triangle*3); fmap.addStaticFloatArray("root_s", m_n_triangle*3); fmap.addStaticFloatArray("root_t", m_n_triangle*3); fmap.addPref(m_n_vertex); fmap.addStaticFloatArray("scale", m_n_vertex); fmap.addStaticFloatArray("curl", m_n_vertex); fmap.addStaticFloatArray("width", m_n_vertex); fmap.addStaticFloatArray("density", m_n_vertex); fmap.staticEndNoWrite(); } delete[] curlarray; delete[] widtharray; delete[] densityarray; // write vertex p string dynamic_path(filename); zGlobal::cutByLastDot(dynamic_path); dynamic_path.append(".hbd"); fmap.dynamicBegin(dynamic_path.c_str()); XYZ* recp = new XYZ[m_n_vertex]; for(int i=0; i<m_n_vertex; i++) recp[i] = XYZ(m_vertex_p[i].x, m_vertex_p[i].y, m_vertex_p[i].z); fmap.addP(m_n_vertex, recp); delete[] recp; // write vertex n XYZ* recn = new XYZ[m_n_vertex]; for(int i=0; i<m_n_vertex; i++) recn[i] = XYZ(m_vertex_n[i].x, m_vertex_n[i].y, m_vertex_n[i].z); fmap.addN(m_n_vertex, recn); delete[] recn; // write veretx tangent XYZ* rect = new XYZ[m_n_vertex]; for(int i=0; i<m_n_vertex; i++) rect[i] = XYZ(m_vertex_t[i].x, m_vertex_t[i].y, m_vertex_t[i].z); fmap.addDynamicVectorArray("direction", m_n_vertex, rect); delete[] rect; // write vertex binormal fmap.addDynamicVectorArray("binormal", m_n_vertex, pbinormal); delete[] pbinormal; // write vertex up // fmap.addDynamicVectorArray("up", m_n_vertex, pup); // delete[] pup; // write vertex wind fmap.addDynamicVectorArray("wind", m_n_vertex, pv); delete[] pv; // write bound box MPoint corner_l, corner_h; getBBox(corner_l, corner_h); fmap.addBBox(corner_l.x, corner_l.y, corner_l.z, corner_h.x, corner_h.y, corner_h.z); fmap.dynamicEnd(); fmap.endMap(filename); char info[256]; sprintf(info, "hairBase writes %s", filename); MGlobal::displayInfo ( info ); m_vertex_id.clear(); m_vertex_p.clear(); m_vertex_n.clear(); m_vertex_t.clear(); delete[] pscale; }
MStatus tm_polySplitFty::doIt() // // Description: // Performs the actual tm_polySplit operation on the given object and UVs // { MStatus status = MS::kSuccess; MVector vector; MPoint point; MFnMesh meshFn( fMesh); int edgeVertices[2]; MItMeshEdge edgeIt( fMesh); int prevIndex; meshFn.getEdgeVertices( fSelEdges[0], edgeVertices); meshFn.getPoint( edgeVertices[0], point); meshFn.getPoint( edgeVertices[1], averagePos); averagePos = (point + averagePos) * 0.5; #ifdef _DEBUG cout << endl << "##########################tm_polySplitFty::doIt" << endl; cout<<"loop="<<fa_loop<<" loopMode="<<fa_loop_mode<<" loop_angle="<<fa_loop_angle<<" loop_maxcount="<<fa_maxcount<<endl; #endif //getting valid edges { if( fa_loop) { if(!getLoopFromFirst( fa_loop_mode, fa_loop_angle, fa_maxcount)) { MGlobal::displayError( "tm_polySplit command failed: Bad edges selected." ); return MStatus::kFailure; } } else { if(!getRing()) { MGlobal::displayError( "tm_polySplit command failed: Bad edges selected." ); return MStatus::kFailure; } } {// close edges: MIntArray conFacesA; edgeIt.setIndex( fSelEdges[0], prevIndex); edgeIt.getConnectedFaces( conFacesA); if( conFacesA.length() > 1) { MIntArray conFacesB; edgeIt.setIndex( fSelEdges[fSelEdges.length() - 1], prevIndex); edgeIt.getConnectedFaces( conFacesB); if( conFacesB.length() > 1) { if( conFacesA[0] == conFacesB[0]) fSelEdges.append( fSelEdges[0]); else if( conFacesA[0] == conFacesB[1]) fSelEdges.append( fSelEdges[0]); else if( conFacesA[1] == conFacesB[0]) fSelEdges.append( fSelEdges[0]); else if( conFacesA[1] == conFacesB[1]) fSelEdges.append( fSelEdges[0]); } } } } #ifdef _DEBUG cout << endl << "fSelEdges = ";for( unsigned i=0;i<fSelEdges.length();i++) cout << fSelEdges[i] << " ";cout << endl; #endif edgesCount = fSelEdges.length(); if(edgesCount < 2) { MGlobal::displayError( "tm_polySplit command failed: Can't find more than one ring edge." ); return MStatus::kFailure; } MItMeshVertex vtxIt( fMesh); MItMeshPolygon faceIt( fMesh); MIntArray conFaces; MIntArray conEdges; MIntArray faceEdges; unsigned numConFaces; if( firstTime) { splitedPoints_start_N.setLength( edgesCount); splitedPoints_dir_N.setLength( edgesCount); splitedPoints_ndir_N.setLength( edgesCount); splitedPoints_start_R.setLength( edgesCount); splitedPoints_dir_R.setLength( edgesCount); splitedPoints_ndir_R.setLength( edgesCount); oldVtxCount = meshFn.numVertices(); oldUVsCount = meshFn.numUVs(); #ifdef _DEBUG cout << endl << "oldVtxCount = " << oldVtxCount << endl; cout << endl << "oldUVsCount = " << oldUVsCount << endl; #endif //######################################## finding inverted edges invEdge.setLength(edgesCount); #ifdef _DEBUG cout << "### finding inverted edges:" << endl; #endif for( unsigned i = 0; i < edgesCount; i++) invEdge[i] = 0; int zero_vtx_index = 0; edgeIt.setIndex( fSelEdges[0], prevIndex); edgeIt.getConnectedFaces( conFaces); numConFaces = conFaces.length(); int nextEdgeId = -1; int nextFaceId = -1; for( unsigned cf = 0; cf < numConFaces; cf++) { faceIt.setIndex( conFaces[cf], prevIndex); faceIt.getEdges( faceEdges); unsigned numFaceEdges = faceEdges.length(); for( unsigned fe = 0; fe < numFaceEdges; fe++) { if( faceEdges[fe] == fSelEdges[1]) { nextFaceId = conFaces[cf]; break; } } if( nextEdgeId != -1) break; } if( nextFaceId == -1) { #ifdef _DEBUG cout << "nextFaceId == -1 (edgeId[" << fSelEdges[0] << "]);" << endl; #endif return MStatus::kFailure; } meshFn.getEdgeVertices( fSelEdges[0], edgeVertices); int vtxIndex = edgeVertices[zero_vtx_index]; unsigned e = 1; bool founded = true; int nextEdgeVertices[2]; int COUNTER = 0; while( e < edgesCount) { COUNTER++; if(COUNTER > 32000) { #ifdef _DEBUG cout << "(COUNTER > 32000) on finding inverted edges!" << endl; #endif break; } meshFn.getEdgeVertices( fSelEdges[e], nextEdgeVertices); vtxIt.setIndex( vtxIndex, prevIndex); vtxIt.getConnectedEdges( conEdges); unsigned numConEdges = conEdges.length(); faceIt.setIndex( nextFaceId, prevIndex); faceIt.getEdges( faceEdges); unsigned numFaceEdges = faceEdges.length(); #ifdef _DEBUG cout << COUNTER << ") edgeId = " << fSelEdges[e-1] << ", numConEdges = " << numConEdges; cout << ", vtxIndex = " << vtxIndex << ", nextFaceId = " << nextFaceId << ":" << endl; #endif bool nextEdgeId_founded = false; for( unsigned ce = 0; ce < numConEdges; ce++) { if((conEdges[ce] == fSelEdges[e-1]) || (conEdges[ce] == nextEdgeId)) continue; for( unsigned fe = 0; fe < numFaceEdges; fe++) { if( conEdges[ce] == faceEdges[fe]) { nextEdgeId = conEdges[ce]; nextEdgeId_founded = true; break; } } if( nextEdgeId_founded) break; } if(!nextEdgeId_founded) { #ifdef _DEBUG cout << "nextEdgeId was not founded, edge " << fSelEdges[e-1] << endl; cout << "connected edges: "; for( unsigned ce = 0; ce < numConEdges; ce++) cout << conEdges[ce] << ", "; cout << endl; cout << "connected face edges: "; for( unsigned fe = 0; fe < numFaceEdges; fe++) cout << faceEdges[fe] << ", "; cout << endl; #endif break; } int cEdgeVertices[2]; meshFn.getEdgeVertices( nextEdgeId, cEdgeVertices); int cEdge_oppVtx; int searchVtxIndex = 1; if( nextEdgeId == fSelEdges[e]) searchVtxIndex = 0; if( cEdgeVertices[0] == vtxIndex) cEdge_oppVtx = cEdgeVertices[1]; else cEdge_oppVtx = cEdgeVertices[0]; #ifdef _DEBUG cout << "nextEdgeId = " << nextEdgeId << ", cEdge_oppVtx = " << cEdge_oppVtx << endl; #endif founded = false; if(cEdge_oppVtx == nextEdgeVertices[searchVtxIndex]) { invEdge[e] = 1; zero_vtx_index = 1; founded = true; } if(cEdge_oppVtx == nextEdgeVertices[1-searchVtxIndex]) { zero_vtx_index = 0; founded = true; } if(!founded) { vtxIndex = cEdge_oppVtx; continue; } if(e == (edgesCount-1)) break; edgeIt.setIndex( fSelEdges[e], prevIndex); edgeIt.getConnectedFaces( conFaces); numConFaces = conFaces.length(); if( numConFaces < 2) { #ifdef _DEBUG cout << "numConFaces < 2 (edgeId[" << fSelEdges[e] << "]);" << endl; #endif break; } if( conFaces[0] == nextFaceId) nextFaceId = conFaces[1]; else nextFaceId = conFaces[0]; vtxIndex = nextEdgeVertices[zero_vtx_index]; e++; #ifdef _DEBUG cout << "founded, conFaces = " << conFaces[0] << ", " << conFaces[1] << " => " << nextFaceId << endl; #endif } } //######################################## getting edges vertices UVs information MFloatArray edgeUVs_u( edgesCount*4, -1.0f); MFloatArray edgeUVs_v( edgesCount*4, -1.0f); MIntArray edge_conFacesIds( edgesCount*2, -1); MIntArray edge_conFacesNum( edgesCount, -1); for( unsigned e = 0; e < edgesCount; e++) { //#ifdef _DEBUG //cout << "edgeId #" << fSelEdges[e] << ":" << endl; //#endif meshFn.getEdgeVertices( fSelEdges[e], edgeVertices); edgeIt.setIndex( fSelEdges[e], prevIndex); edgeIt.getConnectedFaces( conFaces); numConFaces = conFaces.length(); edge_conFacesNum[e] = numConFaces; bool swap = false; if((numConFaces > 1) && (conFaces[0] > conFaces[1])) swap = true; for( unsigned cf = 0; cf < numConFaces; cf++) { int cFaceId = cf; if( swap) cFaceId = 1 - cf; edge_conFacesIds[e*2 + cf] = conFaces[cFaceId]; for( int ev = 0; ev < 2 ; ev++) { int numVtxUVs; float uvPiont[2]; vtxIt.setIndex( edgeVertices[ev], prevIndex); vtxIt.numUVs( numVtxUVs); if( numVtxUVs <= 0) continue; MStatus stat = vtxIt.getUV( conFaces[cFaceId], uvPiont); if(!stat) continue; unsigned uvArrayIndex = (e*4) + (cf*2) + ev; edgeUVs_u.set( uvPiont[0], uvArrayIndex); edgeUVs_v.set( uvPiont[1], uvArrayIndex); //#ifdef _DEBUG //cout << "faceId #" << conFaces[cFaceId] << ", vtxId #" << edgeVertices[ev] << " = ("; //cout << edgeUVs_u[uvArrayIndex] << ", " << edgeUVs_v[uvArrayIndex] << ");" << endl; //#endif } } } //###################################### get points starts and vectors: for( unsigned i = 0; i < edgesCount; i++) { meshFn.getEdgeVertices( fSelEdges[i], edgeVertices); if ( invEdge[i] == 1) { meshFn.getPoint( edgeVertices[1], splitedPoints_start_N[i]); meshFn.getPoint( edgeVertices[0], point); } else { meshFn.getPoint( edgeVertices[0], splitedPoints_start_N[i]); meshFn.getPoint( edgeVertices[1], point); } splitedPoints_dir_N[i] = point - splitedPoints_start_N[i]; splitedPoints_ndir_N[i] = splitedPoints_dir_N[i]; splitedPoints_ndir_N[i].normalize(); splitedPoints_start_R[i] = point; splitedPoints_dir_R[i] = splitedPoints_start_N[i] - point; splitedPoints_ndir_R[i] = splitedPoints_dir_R[i]; splitedPoints_ndir_R[i].normalize(); } /* #ifdef _DEBUG cout << endl << "splitedPoints_start_N = "; for( unsigned i=0;i<splitedPoints_start_N.length();i++) cout << splitedPoints_start_N[0]<<","<<splitedPoints_start_N[1]<<","<<splitedPoints_start_N[2] << " "; cout << endl << "splitedPoints_dir_N = "; for( unsigned i=0;i<splitedPoints_dir_N.length();i++) cout << splitedPoints_dir_N[0]<<","<<splitedPoints_dir_N[1]<<","<<splitedPoints_dir_N[2] << " "; cout << endl; #endif */ //######################################## do the split: MFloatPointArray internalPoints; MIntArray placements( edgesCount, MFnMesh::kOnEdge); MFloatArray edgeFactors( edgesCount, 0.5); status = meshFn.split( placements, fSelEdges, edgeFactors, internalPoints); if( !status) { MGlobal::displayError( "can't split with given data"); return status; } #ifdef _DEBUG cout << endl << " ! split success ! " << endl; #endif newVtxCount = meshFn.numVertices(); newUVsCount = meshFn.numUVs(); //###################################### get UVs starts and vectors: #ifdef _DEBUG cout << endl << "newVtxCount = " << newVtxCount << endl; cout << endl << "newUVsCount = " << newUVsCount << endl; #endif unsigned edgeNum = 0; unsigned uvNum = 0; unsigned numNewUVs = newUVsCount - oldUVsCount; splitedUVsU_start_N.setLength( numNewUVs); splitedUVsV_start_N.setLength( numNewUVs); splitedUVsU_start_R.setLength( numNewUVs); splitedUVsV_start_R.setLength( numNewUVs); splitedUVsU_dir_N.setLength( numNewUVs); splitedUVsV_dir_N.setLength( numNewUVs); splitedUVsU_dir_R.setLength( numNewUVs); splitedUVsV_dir_R.setLength( numNewUVs); splitedUVsU_ndir_N.setLength( numNewUVs); splitedUVsV_ndir_N.setLength( numNewUVs); splitedUVsU_ndir_R.setLength( numNewUVs); splitedUVsV_ndir_R.setLength( numNewUVs); for( int j = oldVtxCount; j < newVtxCount; j++) { MIntArray conFaces; int numVtxUVs; vtxIt.setIndex( j, prevIndex); vtxIt.numUVs( numVtxUVs); if( numVtxUVs > 0) { //#ifdef _DEBUG //cout << "vtx #" << j << " (edge #" << fSelEdges[edgeNum] << ") :" << endl; //#endif bool swap = false; if((edge_conFacesNum[edgeNum] > 1) && (numVtxUVs > 1)) { MItMeshPolygon faceIt( fMesh); faceIt.setIndex( edge_conFacesIds[edgeNum*2], prevIndex); int numFaceVtx = faceIt.polygonVertexCount(); bool has = false; //#ifdef _DEBUG //cout << "((numConFaces > 1) && (numVtxUVs > 1)) : ( "; //#endif for( int fVtx = 0; fVtx < numFaceVtx; fVtx++) { int uvIndex; faceIt.getUVIndex( fVtx, uvIndex); //#ifdef _DEBUG //cout << uvIndex << " "; //#endif if( uvIndex == (uvNum + oldUVsCount)) has = true; } if( !has) swap = true; //#ifdef _DEBUG //cout << ") uv = " << (uvNum + oldUVsCount) << " => swap = " << swap << endl; //#endif } for( int uvi = 0; uvi < numVtxUVs; uvi++) { unsigned uvArrayIndex_a; if( swap) uvArrayIndex_a = (edgeNum*4) + ((1-uvi)*2); else uvArrayIndex_a = (edgeNum*4) + (uvi*2); unsigned uvArrayIndex_b = uvArrayIndex_a; if(invEdge[edgeNum] == 1) uvArrayIndex_a++; else uvArrayIndex_b++; splitedUVsU_start_N[uvNum] = edgeUVs_u[uvArrayIndex_a]; splitedUVsV_start_N[uvNum] = edgeUVs_v[uvArrayIndex_a]; splitedUVsU_start_R[uvNum] = edgeUVs_u[uvArrayIndex_b]; splitedUVsV_start_R[uvNum] = edgeUVs_v[uvArrayIndex_b]; splitedUVsU_dir_N[uvNum] = edgeUVs_u[uvArrayIndex_b] - edgeUVs_u[uvArrayIndex_a]; splitedUVsV_dir_N[uvNum] = edgeUVs_v[uvArrayIndex_b] - edgeUVs_v[uvArrayIndex_a]; splitedUVsU_dir_R[uvNum] = edgeUVs_u[uvArrayIndex_a] - edgeUVs_u[uvArrayIndex_b]; splitedUVsV_dir_R[uvNum] = edgeUVs_v[uvArrayIndex_a] - edgeUVs_v[uvArrayIndex_b]; float dist = sqrt((splitedUVsU_dir_N[uvNum]*splitedUVsU_dir_N[uvNum]) + (splitedUVsV_dir_N[uvNum]*splitedUVsV_dir_N[uvNum])); if(dist == 0) { splitedUVsU_ndir_N[uvNum] = 0; splitedUVsV_ndir_N[uvNum] = 0; splitedUVsU_ndir_R[uvNum] = 0; splitedUVsV_ndir_R[uvNum] = 0; } else { splitedUVsU_ndir_N[uvNum] = splitedUVsU_dir_N[uvNum] / dist; splitedUVsV_ndir_N[uvNum] = splitedUVsV_dir_N[uvNum] / dist; splitedUVsU_ndir_R[uvNum] = splitedUVsU_dir_R[uvNum] / dist; splitedUVsV_ndir_R[uvNum] = splitedUVsV_dir_R[uvNum] / dist; } /*#ifdef _DEBUG cout << "uvNum #" << (uvNum + oldUVsCount) << " (uvi=" << uvi << ") : ( "; cout << edgeUVs_u[uvArrayIndex_a] << ", "; cout << edgeUVs_v[uvArrayIndex_a] << ") - ( "; cout << edgeUVs_u[uvArrayIndex_b] << ", "; cout << edgeUVs_v[uvArrayIndex_b] << ");" << endl; #endif */ uvNum++; } } edgeNum++; } //################################################################################## return status; }
bool tm_polygon_edgestoring::calculate( MIntArray &edgesArray) { if(!objectIsSet) { MGlobal::displayError("tm_polygon_edgestoring::calculate - Object is not set."); return false; } MFnMesh meshFn( meshObject); MItMeshEdge edgeIt(meshObject); MItMeshPolygon faceIt(meshObject); unsigned numInputEdges = edgesArray.length(); int *visitedEdges = new int[numInputEdges]; for( unsigned e = 0; e < numInputEdges; e++) visitedEdges[e] = 0; std::list <int> ringEdgesList; int prevIndex; MIntArray faces; MIntArray edgeFaces; MIntArray faceEdges; int edgeIndex = edgesArray[0]; ringEdgesList.push_back( edgeIndex); visitedEdges[0] = 1; edgeIt.setIndex( edgeIndex, prevIndex); edgeIt.getConnectedFaces( faces); unsigned numFaces = faces.length(); unsigned numFaceEdges; for( unsigned face = 0; face < numFaces; face++) { edgeIndex = edgesArray[0]; int lastFace, newFace; if( face == 1) lastFace = faces[0]; else lastFace = -1; unsigned COUNTER = 0; while( COUNTER < 32000) { COUNTER++; edgeIt.setIndex( edgeIndex, prevIndex); edgeIt.getConnectedFaces( edgeFaces); if(edgeFaces.length() > 1) { if( edgeFaces[0] == lastFace) newFace = edgeFaces[1]; else newFace = edgeFaces[0]; } else newFace = edgeFaces[0]; faceIt.setIndex( newFace, prevIndex); lastFace = newFace; bool founded = false; for( unsigned e = 0; e < numInputEdges; e++) { if( edgesArray[e] == edgeIndex) continue; if( visitedEdges[e] == 1) continue; faceIt.getEdges( faceEdges); numFaceEdges = faceEdges.length(); for( unsigned fe = 0; fe < numFaceEdges; fe++) { if( faceEdges[fe] == edgesArray[e]) { founded = true; edgeIndex = edgesArray[e]; visitedEdges[e] = 1; if( face == 0) ringEdgesList.push_front( edgeIndex); else ringEdgesList.push_back( edgeIndex); } if( founded) break; } if( founded) break; } if(!founded) break; } } if (visitedEdges != NULL) delete [] visitedEdges; unsigned numRingEdges = (unsigned)ringEdgesList.size(); edgesArray.setLength( numRingEdges); for( unsigned e = 0; e < numRingEdges; e++) { edgesArray[e] = *ringEdgesList.begin(); ringEdgesList.pop_front(); } return true; }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- MStatus CVstSelectCoincidentFacesCmd::DoSelect() { MSelectionList meshList; GetSpecifiedMeshes( meshList ); MSelectionList coincidentList; MDagPath mDagPath; MObject cObj; MPointArray points; MIntArray iIndexes; MIntArray jIndexes; uint iCount; bool addI; bool same; bool foundVertex; double tolerance( MPoint_kTol ); if ( m_undo.ArgDatabase().isFlagSet( kOptTolerance ) ) { MDistance optTolerance; m_undo.ArgDatabase().getFlagArgument( kOptTolerance, 0U, optTolerance ); tolerance = optTolerance.as( MDistance::internalUnit() ); } for ( MItSelectionList sIt( meshList ); !sIt.isDone(); sIt.next() ) { if ( !sIt.getDagPath( mDagPath, cObj ) ) continue; MFnSingleIndexedComponent sFn; MObject sObj( sFn.create( MFn::kMeshPolygonComponent ) ); MFnMesh meshFn( mDagPath ); meshFn.getPoints( points ); if ( !sIt.hasComponents() ) { const uint nFaces( meshFn.numPolygons() ); for ( uint i( 0U ); i != nFaces; ++i ) { meshFn.getPolygonVertices( i, iIndexes ); iCount = iIndexes.length(); addI = false; for ( uint j( i + 1 ); j < nFaces; ++j ) { meshFn.getPolygonVertices( j, jIndexes ); if ( jIndexes.length() == iCount ) { same = true; for ( uint k( 0U ); k != iCount; ++k ) { foundVertex = false; const MPoint &kPoint( points[ iIndexes[ k ] ] ); for ( uint l( 0U ); l < iCount; ++l ) { if ( kPoint.isEquivalent( points[ jIndexes[ l ] ], tolerance ) ) { foundVertex = true; break; } } if ( !foundVertex ) { same = false; break; } } if ( same ) { addI = true; sFn.addElement( j ); } } } if ( addI ) { sFn.addElement( i ); } } } else { MFnSingleIndexedComponent cFn( cObj ); MIntArray cA; MFnSingleIndexedComponent( cObj ).getElements( cA ); const uint nFaces( cA.length() ); for ( uint i( 0U ); i != nFaces; ++i ) { meshFn.getPolygonVertices( cA[ i ], iIndexes ); iCount = iIndexes.length(); addI = false; for ( uint j( i + 1U ); j < nFaces; ++j ) { meshFn.getPolygonVertices( cA[ j ], jIndexes ); if ( jIndexes.length() == iCount ) { same = true; for ( uint k( 0U ); k != iCount; ++k ) { foundVertex = false; const MPoint &kPoint( points[ iIndexes[ k ] ] ); for ( uint l( 0U ); l < iCount; ++l ) { if ( kPoint.isEquivalent( points[ jIndexes[ l ] ], tolerance ) ) { foundVertex = true; break; } } if ( !foundVertex ) { same = false; break; } } if ( same ) { addI = true; sFn.addElement( cA[ j ] ); } } } if ( addI ) { sFn.addElement( cA[ i ] ); } } } if ( sFn.elementCount() > 0 ) { coincidentList.add( mDagPath, sObj ); } else { MSelectionList tmpList; tmpList.add( mDagPath, cObj ); MStringArray tmpA; tmpList.getSelectionStrings( tmpA ); minfo << "No coincident faces on:"; for ( uint i( 0U ); i != tmpA.length(); ++i ) { minfo << " " << tmpA[ i ]; } minfo << std::endl; } } if ( coincidentList.length() ) { MGlobal::setActiveSelectionList( coincidentList ); MStringArray tmpA; coincidentList.getSelectionStrings( tmpA ); setResult( tmpA ); } else { if ( meshList.length() > 0U ) { minfo << "No coincident faces found" << std::endl; } } return MS::kSuccess; }
void VMesh::draw() { if(!has_mesh) return; MStatus status; MFnMesh meshFn(pgrow, &status ); MItMeshVertex vertIter(pgrow, &status); MPoint S; MVector N, tang, ttang, binormal, dir, hair_up; MColor Cscale, Cerect, Crotate, Ccurl; float rot; MATRIX44F hair_space; MString setScale("fb_scale"); MString setErect("fb_erect"); MString setRotate("fb_rotate"); MString setCurl("fb_curl"); MIntArray conn_face; glBegin(GL_LINES); for( int i=0; !vertIter.isDone(); vertIter.next(), i++ ) { //S = vertIter.position(MSpace::kWorld); //glVertex3f(S.x, S.y, S.z); vertIter.getNormal(N, MSpace::kWorld); N.normalize(); vertIter.getColor(Cscale, &setScale); vertIter.getColor(Cerect, &setErect); vertIter.getColor(Crotate, &setRotate); vertIter.getColor(Ccurl, &setCurl); vertIter.getConnectedFaces(conn_face); tang = MVector(0,0,0); for(int j=0; j<conn_face.length(); j++) { meshFn.getFaceVertexTangent (conn_face[j], i, ttang, MSpace::kWorld); ttang.normalize(); tang += ttang; } tang /= conn_face.length(); conn_face.clear(); tang.normalize(); tang = N^tang; tang.normalize(); binormal = N^tang; if(Crotate.r<0.5) { rot = (0.5 - Crotate.r)*2; tang = tang + (binormal-tang)*rot; tang.normalize(); binormal = N^tang; } else { rot = (Crotate.r-0.5)*2; tang = tang + (binormal*-1-tang)*rot; tang.normalize(); binormal = N^tang; } dir = tang + (N - tang)*Cerect.r; dir.normalize(); //S = S+dir*Cscale.r*m_scale; //glVertex3f(S.x, S.y, S.z); hair_up = dir^binormal; hair_space.setIdentity(); hair_space.setOrientations(XYZ(binormal.x, binormal.y, binormal.z), XYZ(hair_up.x, hair_up.y, hair_up.z), XYZ(dir.x, dir.y, dir.z)); S = vertIter.position(MSpace::kWorld); hair_space.setTranslation(XYZ(S.x, S.y, S.z)); fb->create(Cscale.r*m_scale, 0, Cscale.r*m_scale*(Ccurl.r-0.5)*2); XYZ pw; for(int j=0; j<NUMBENDSEG; j++) { fb->getPoint(j, pw); hair_space.transform(pw); glVertex3f(pw.x, pw.y, pw.z); fb->getPoint(j+1, pw); hair_space.transform(pw); glVertex3f(pw.x, pw.y, pw.z); } } glEnd(); }
//---------------------------------------------------------------------------- MStatus BPT_InsertVtx::doCompleteCompute( MDataBlock& data ) //---------------------------------------------------------------------------- { SPEED("Berechne EdgeSplit neu: "); MStatus status; MPRINT("MACHE KOMPLETTE BERECHNUNG") MDataHandle inMeshHandle = data.inputValue(IVinMesh); MDataHandle outMeshHandle = data.outputValue(IVoutMesh); //splitCount setzen MDataHandle countHandle = data.inputValue(IVcount); fIVfty.setCount(countHandle.asInt()); MDataHandle spinHandle = data.inputValue(IVspin); fIVfty.setSpin(spinHandle.asInt()); int initialVtxCount; //wird spueueter benueuetigt, um das ValidIndicesArray gleich in der rictigen grueueueuee zu erstellen und zu schreiben //gleich zu beginn muss der MeshPath initialisiert werden, damit der MeshPath an die fty ueuebergeben werden kann // Dies geschieht besser durch die STE - sie ist darauf ausgelegt softTransformationEngine::gatherAttributeObjects(thisMObject()); softTransformationEngine::saveMeshPathes(); fIVfty.setMeshPath(meshPath); MDataHandle rHandle = data.inputValue(IVslideRelative); fIVfty.setRelative(rHandle.asInt()); MDataHandle nRelativeHandle = data.inputValue(IVnormalRelative); fIVfty.setNormalRelative(nRelativeHandle.asInt()); //selection setzen MFnIntArrayData intDataArray; MDataHandle arrayHandle = data.inputValue(IVselEdgeIDs); intDataArray.setObject(arrayHandle.data()); fIVfty.setEdgeIDs( intDataArray.array() ); arrayHandle = data.inputValue(IVselVertIDs); intDataArray.setObject(arrayHandle.data()); fIVfty.setVertIDs(intDataArray.array()); // optionen holen arrayHandle = data.inputValue(IVoptions); intDataArray.setObject(arrayHandle.data()); MIntArray optionsArray(intDataArray.array()); fIVfty.setOptions(optionsArray); MDataHandle slideHandle = data.inputValue(IVslide); fIVfty.setSlide(slideHandle.asDouble()); //whichSide attribute wird nur fueuer SLide selbst verwendet und kann nicht bereits beim command gestetzt werden MObject inMeshRef = inMeshHandle.asMesh(); fIVfty.setMesh(inMeshRef); MFnMesh meshFn(inMeshHandle.asMesh()); initialVtxCount = meshFn.numVertices(); //ACTION try { status = fIVfty.doIt(); } catch(...) { MGlobal::displayError(" An unknown, severe, error occoured.\nIf it happens again in this situation, please write a bug report.\nPlease undo the operation and save your work!"); return MS::kUnknownParameter; } MObject newOutMesh = fIVfty.getMesh(); outMeshHandle.set(newOutMesh); // --------------------- // SOFT TRANSFORMATION // --------------------- // VtxSet setzen - hier reicht es, wenn er einfach die neuen Vtx nimmt softTransformationEngine::setVtxSet(data); //------------SELECTION ROUTINE---------------------- //nur wenn sich spin nicht verueuendert hat, darf ne neue selection gemacht werden - dies wird auch von der IV berueuecksichtigt //die selection wird nur noch einmal ausgefueuehrt, weshalb scriptJobInitiated nicht mehr gesetzt wird vom scriptjob if( optionsArray[6] && !scriptJobInitated && !(meshPath.apiType() == MFn::kInvalid) ) { //auf jeden Fall erstmal die neuen Vertizen holen, damit die anderen prozeduren auch darauf arbeiten kueuennen //alles neuen Vertces sollen gewueuehlt werden, also einfach alle Indices eintragen vom initialVtxCount //bis zum jetzigen VtxCount MIntArray validEdges, validFaces; componentConverter CC(newOutMesh); int i = 0; meshFn.setObject(newOutMesh); int newCount = meshFn.numVertices(); validIndices.clear(); validIndices.setLength(newCount - initialVtxCount); for(; initialVtxCount < newCount; initialVtxCount++) validIndices[i++] = initialVtxCount; if(optionsArray[6] == 1 || optionsArray[6] == 2) //select edges { CC.getContainedEdges(validIndices,validEdges); } BPT_Helpers helper; if(optionsArray[6] == 2) //select Faces { CC.getConnectedFaces(validEdges,validFaces); //jetzt kann gleich alles beendet werden, da hiernach keine componente mehr kommt, in die man faces umwandeln mueuesste validIndices.clear(); validIndices.append(2); helper.addIntArrayToLHS(validIndices,validFaces); } if(optionsArray[6] == 1) {//edges fertigmachen validIndices.clear(); validIndices.append(1); helper.addIntArrayToLHS(validIndices,validEdges); } else if(optionsArray[6] == 5) validIndices.insert(3,0); //component Mode umschalten bei bedarf if(optionsArray[5]) { MSelectionMask::SelectionType type = MSelectionMask::kSelectMeshVerts; if(optionsArray[6] == 5) { type = MSelectionMask::kSelectMeshVerts; } else if(optionsArray[6] == 2) { type = MSelectionMask::kSelectMeshFaces; } else if(optionsArray[6] == 1) { type = MSelectionMask::kSelectMeshEdges; } MSelectionMask mask(type); MGlobal:: setComponentSelectionMask(mask); } eID = MEventMessage::addEventCallback("idle",IV_makeSelection,this); scriptJobInitated = true; } else {//ansonsten muss die SelectionList neu aufgebaut werden, allerdings ohne komponenten //diese Aktion solte auch nur einmal ausgefueuehrt werden //gegenwueuertige selection holen MSelectionList currentList; MSelectionList newList; MGlobal::getActiveSelectionList(currentList); //durch die Liste iterieren und Komponenten Filtern MItSelectionList selIter(currentList); MObject currentObj; for( ; !selIter.isDone();selIter.next() ) { selIter.getDependNode(currentObj); newList.add(currentObj); } MGlobal::setActiveSelectionList(newList, MGlobal::kAddToList); } return status; }
void OsdPtexMeshData::rebuildHbrMeshIfNeeded(OpenSubdivPtexShader *shader) { MStatus status; if (!_meshTopoDirty && !shader->getHbrMeshDirty()) return; MFnMesh meshFn(_meshDagPath, &status); if (status != MS::kSuccess) return; int level = shader->getLevel(); if (level < 1) level =1; SchemeType scheme = shader->getScheme(); if (scheme == kLoop) scheme = kCatmark; // XXX: avoid loop for now // Get Maya vertex topology and crease data MIntArray vertexCount; MIntArray vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData); if (vertexCount.length() == 0) return; // Cache attribute values _level = shader->getLevel(); _scheme = shader->getScheme(); _kernel = shader->getKernel(); _adaptive = shader->isAdaptive(); _interpBoundary = shader->getInterpolateBoundary(); // Copy Maya vectors into std::vectors std::vector<int> numIndices(&vertexCount[0], &vertexCount[vertexCount.length()]); std::vector<int> faceIndices(&vertexList[0], &vertexList[vertexList.length()]); std::vector<int> vtxCreaseIndices(&vtxIds[0], &vtxIds[vtxIds.length()]); std::vector<double> vtxCreases(&vtxCreaseData[0], &vtxCreaseData[vtxCreaseData.length()]); std::vector<double> edgeCreases(&edgeCreaseData[0], &edgeCreaseData[edgeCreaseData.length()]); // Edge crease index is stored as pairs of vertex ids int nEdgeIds = edgeIds.length(); std::vector<int> edgeCreaseIndices; edgeCreaseIndices.resize(nEdgeIds*2); for (int i = 0; i < nEdgeIds; ++i) { int2 vertices; status = meshFn.getEdgeVertices(edgeIds[i], vertices); if (status.error()) { status.perror("ERROR can't get creased edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } // Convert attribute enums to HBR enums (this is why the enums need to match) // XXX use some sort of built-in transmorgification avoid assumption? HbrMeshUtil::SchemeType hbrScheme = (HbrMeshUtil::SchemeType) _scheme; OsdHbrMesh::InterpolateBoundaryMethod hbrInterpBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) _interpBoundary; // Convert Maya mesh to internal HBR representation _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, hbrInterpBoundary, hbrScheme, true ); // add ptex indices to HBR // note: GL function can't be used in prepareForDraw API. _needsInitializeMesh = true; // Mesh topology data is up to date _meshTopoDirty = false; shader->setHbrMeshDirty(false); }
//----------------------------------------------------------------- MStatus ByronsPolyTools::doIt(const MArgList& args) //----------------------------------------------------------------- { // Ist die version abgelaufen ? // #ifdef EXPIRES if( ! checkExpires() ) { MGlobal::displayError( "This AlphaVersion is expired. Scenes will still load properly. " ); return MS::kSuccess; } #endif MSelectionList sList; MStatus status; MArgDatabase argData(syntax(),args); if(argData.isFlagSet("-help")) { MGlobal::executeCommand("showBPTHelpWindow",false,false); return MS::kSuccess; } //SELECTION UEBERPRUEFEN // Selection holen // argData.getObjects(sList); // OrigList fuer UndoZwecke speichern origList = sList; // Check, ob ueberhaupt Objekt gewaehlt if ( (sList.length() == 0) ) { displayError("ONE mesh or its transform node must be selected."); return MStatus::kFailure; } //MDagPath meshDagPath; MItSelectionList sIter(sList);//,MFn::kMesh); bool meshOK = false,hasComps = false; INVIS(cout<<"SELECTIONLIST LAENGE: "<<sList.length()<<endl); for(; !sIter.isDone(); sIter.next()) { sIter.getDagPath(meshDagPath, components); //sList.getDagPath(0, meshDagPath, components); //if(!meshDagPath.hasFn(MFn::kPluginDependNode)) if(meshDagPath.apiType() == (MFn::kMesh)) { if(!meshDagPath.hasFn(MFn::kMesh) ) meshOK = false; else meshOK = true; if( components.apiType() == MFn::kInvalid ) hasComps = false; else { hasComps = true; break; } } } if(!meshOK) { displayError("Invalid type! Only a mesh or its transform with selected components can be specified!"); return MStatus::kFailure; } #ifdef DEMO MFnMesh meshFn(meshDagPath); if(meshFn.numPolygons() > 500) { MGlobal::displayError("This DEMO will only work on meshes with a maximum number of 500 polygons"); return MS::kFailure; } #endif if(!hasComps) { displayError("Please select some components to operate on"); return MStatus::kFailure; } // Flags und Argumente Holen //---------------------------------- if(argData.isFlagSet("-iv")) operationMode = 0; else operationMode = 1; //zuerst mal edgeComoponents holen - wenn welche vorhanden und -peb flag gesetzt, dann wird auf jeden Fall der case 0 mode verwendet getEdgeComponents(sList); if( argData.isFlagSet("-peb") && edgeIDs.length() != 0 ) operationMode = 0; //------------------------------------ // OPTIONS //------------------------------------ switch(operationMode) { case 0://insert Vtx mode { if(argData.isFlagSet("-ic")) argData.getFlagArgument("-ic",0,initialCount); else initialCount = 1; goto default_values; } case 1: //PolyToolsMode { //------------------------------------ // FLAGS //------------------------------------ smartSplitFlagSet = argData.isFlagSet("-smartSplit"); edgeLoopFlagSet = argData.isFlagSet("-edgeLoop"); edgeRingFlagSet = argData.isFlagSet("-edgeRing"); boundaryFlagSet = argData.isFlagSet("-boundary"); chamferFlagSet = argData.isFlagSet("-chamfer"); solidChamferFlagSet = argData.isFlagSet("-solidChamfer"); smcFlagSet = argData.isFlagSet("-smartMoveComponent"); growFlagSet = argData.isFlagSet("-gro"); schrinkFlagSet = argData.isFlagSet("-shr"); // abbruch, wenn flags nicht eindeutig und actionMode nicht gesetzt werden kann status = setActionMode(); if(status == MS::kFailure) return status; //-------------------ENDE----------------------------- goto default_values; } default: { default_values: avt = (argData.isFlagSet("-avf"))?true:false; avm = (argData.isFlagSet("-avm"))?true:false; options.setLength(10); options[0] = argData.isFlagSet("-connectEnds"); options[1] = argData.isFlagSet("-triangulateEnds"); if(argData.isFlagSet("-maxEdgeCount")) argData.getFlagArgument("-maxEdgeCount",0,options[2]); else options[2] = 16666666; options[3] = 0; //side ist standardmaessig 0: if(argData.isFlagSet("-snl") ) options[4] = 1; else options[4] = 0; options[5] = (argData.isFlagSet("-ast"))?1:0; options[6] = 0; if(argData.isFlagSet("-se")) options[6] = 1; if( CMDactionMode == 5 && argData.isFlagSet("-") ) options[6] += 3; if(argData.isFlagSet("-sf")) options[6] = 2; if(argData.isFlagSet("-sv")) options[6] = 5; //IV flag - wenn -peb aktiv ist, wird er auf jeden Fall gesetzt if( argData.isFlagSet("-peb") ) options[9] = 1; else options[9] = argData.isFlagSet("-civ")?true:false; //----------------------------------------OPTIONS ENDE slideIsRelative = argData.isFlagSet("-sir"); //slideIsRelative ist an, wenn Chamfer aktiv ist if(chamferFlagSet+solidChamferFlagSet > 0) slideIsRelative = 1; if(CMDactionMode == 6) slideIsRelative = true; normalIsRelative = argData.isFlagSet("-nir"); //slide soll automatisch auf gesetzt werden, wenn -peb aktiv (dies entspricht einem slidewert von 1 if( argData.isFlagSet("-peb") && edgeIDs.length() != 0) directSlide = 1; else { if(argData.isFlagSet("-slide")) argData.getFlagArgument("-slide",0,directSlide); else directSlide = 0.5; //defaultValue } } } //undoIndo sammeln MSelectionMask tmpMask(MGlobal::componentSelectionMask()); undoMask = tmpMask; /* CallWindowProc( (WNDPROC)(GetWindowLong(mayaWin, GWL_WNDPROC)), mayaWin, WM_CLOSE, NULL, NULL); DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; //MessageBox(mayaWin, "Help", "Whatever", MB_OK); HWND myWin = CreateWindowEx( 0,"MyFirstWin","Lala" , dwStyle, 0, 0, 300, 400, mayaWin, NULL, NULL, NULL); ShowWindow(myWin, SW_SHOWNORMAL); SetFocus(myWin); UpdateWindow(myWin); */ //checken ob makeHistory aus ist. Wenn ja, dann wieder an machen, weil maya sonst crashed int result; MGlobal::executeCommand( "constructionHistory -q -tgl", result ); if(!result) MGlobal::executeCommand( "constructionHistory -tgl 1",false,false); meshDagPath.extendToShape(); // Mesh von polyModifierCommand setzen setMeshNode(meshDagPath); switch(operationMode) { case 0: { //getEdgeComponents(sList); convertToEdges(sList, argData.isFlagSet("-peb") ); // setCreateAnimCurves(false);//damit nicht versucht wird, auf dieser Node animCurves fuer tweak zu erstellen // Jetzt sind tweaks vonnten setModifierNodeType( BPT_InsertVtx::IVid ); break; } case 1: { // Komponenten herausfiltern und IntIDArrays schreiben //getEdgeComponents(sList); getVertComponents(sList); getPolyComponents(sList); setModifierNodeType( ByronsPolyToolsNode::id ); break; } } // Aktion ausfuehren if(CMDactionMode == 0 || CMDactionMode == 4 || CMDactionMode == 5 || CMDactionMode == 6 || operationMode == 0) { MGlobal::executeCommand("setToolTo selectSuperContext",false,false); status = doModifyPoly(); MFnDependencyNode depNodeFn(bptNode); setResult(depNodeFn.name()); if( !(status == MS::kSuccess) ) { MGlobal::displayError( "An error occoured." ); MGlobal::displayError( status.errorString() ); } } else { // Wenn mesh nicht veraendert wird, wird einfach so die Factory gerufen directModifier(meshDagPath.node()); //setResult( "BPTOperation succeeded" ); } //Command wird nur einmal verwendet, also muessen die Datenarrays auch m#keinen Speicher mehr verschwenden //.clear() wuerde sie nicht physisch loeschen polyIDs.setLength(0); edgeIDs.setLength(0); vertIDs.setLength(0); // return status; return MS::kSuccess; }
void MayaObject::getMeshData(MPointArray& points, MFloatVectorArray& normals, MFloatArray& uArray, MFloatArray& vArray, MIntArray& triPointIndices, MIntArray& triNormalIndices, MIntArray& triUvIndices, MIntArray& triMatIndices) { MStatus stat; MObject meshObject = this->mobject; MMeshSmoothOptions options; MFnMesh tmpMesh(this->mobject, &stat); MFnMeshData meshData; MObject dataObject; MObject smoothedObj; // create smooth mesh if needed if (tmpMesh.findPlug("displaySmoothMesh").asBool()) { stat = tmpMesh.getSmoothMeshDisplayOptions(options); if (stat) { if (!tmpMesh.findPlug("useSmoothPreviewForRender", false, &stat).asBool()) { //Logging::debug(MString("useSmoothPreviewForRender turned off")); int smoothLevel = tmpMesh.findPlug("renderSmoothLevel", false, &stat).asInt(); options.setDivisions(smoothLevel); } if (options.divisions() > 0) { dataObject = meshData.create(); smoothedObj = tmpMesh.generateSmoothMesh(dataObject, &options, &stat); if (stat) { meshObject = smoothedObj; } } } } MFnMesh meshFn(meshObject, &stat); CHECK_MSTATUS(stat); MItMeshPolygon faceIt(meshObject, &stat); CHECK_MSTATUS(stat); meshFn.getPoints(points); meshFn.getNormals(normals, MSpace::kObject); meshFn.getUVs(uArray, vArray); uint numVertices = points.length(); uint numNormals = normals.length(); uint numUvs = uArray.length(); //Logging::debug(MString("numVertices ") + numVertices); //Logging::debug(MString("numNormals ") + numNormals); //Logging::debug(MString("numUvs ") + numUvs); // some meshes may have no uv's // to avoid problems I add a default uv coordinate if (numUvs == 0) { Logging::warning(MString("Object has no uv's: ") + this->shortName); uArray.append(0.0); vArray.append(0.0); } for (uint nid = 0; nid < numNormals; nid++) { if (normals[nid].length() < 0.1f) Logging::warning(MString("Malformed normal in ") + this->shortName); } MPointArray triPoints; MIntArray triVtxIds; MIntArray faceVtxIds; MIntArray faceNormalIds; for (faceIt.reset(); !faceIt.isDone(); faceIt.next()) { int faceId = faceIt.index(); int numTris; faceIt.numTriangles(numTris); faceIt.getVertices(faceVtxIds); int perFaceShadingGroup = 0; if (this->perFaceAssignments.length() > 0) perFaceShadingGroup = this->perFaceAssignments[faceId]; MIntArray faceUVIndices; faceNormalIds.clear(); for (uint vtxId = 0; vtxId < faceVtxIds.length(); vtxId++) { faceNormalIds.append(faceIt.normalIndex(vtxId)); int uvIndex; if (numUvs == 0) { faceUVIndices.append(0); } else{ faceIt.getUVIndex(vtxId, uvIndex); //if (uvIndex > uArray.length()) // Logging::info(MString("-----------------> UV Problem!!! uvIndex ") + uvIndex + " > uvArray in object " + this->shortName); faceUVIndices.append(uvIndex); } } for (int triId = 0; triId < numTris; triId++) { int faceRelIds[3]; faceIt.getTriangle(triId, triPoints, triVtxIds); for (uint triVtxId = 0; triVtxId < 3; triVtxId++) { for (uint faceVtxId = 0; faceVtxId < faceVtxIds.length(); faceVtxId++) { if (faceVtxIds[faceVtxId] == triVtxIds[triVtxId]) { faceRelIds[triVtxId] = faceVtxId; } } } uint vtxId0 = faceVtxIds[faceRelIds[0]]; uint vtxId1 = faceVtxIds[faceRelIds[1]]; uint vtxId2 = faceVtxIds[faceRelIds[2]]; uint normalId0 = faceNormalIds[faceRelIds[0]]; uint normalId1 = faceNormalIds[faceRelIds[1]]; uint normalId2 = faceNormalIds[faceRelIds[2]]; uint uvId0 = faceUVIndices[faceRelIds[0]]; uint uvId1 = faceUVIndices[faceRelIds[1]]; uint uvId2 = faceUVIndices[faceRelIds[2]]; triPointIndices.append(vtxId0); triPointIndices.append(vtxId1); triPointIndices.append(vtxId2); triNormalIndices.append(normalId0); triNormalIndices.append(normalId1); triNormalIndices.append(normalId2); triUvIndices.append(uvId0); triUvIndices.append(uvId1); triUvIndices.append(uvId2); triMatIndices.append(perFaceShadingGroup); //Logging::debug(MString("vtxIds ") + vtxId0 + " " + vtxId1 + " " + vtxId2); //Logging::debug(MString("nIds ") + normalId0 + " " + normalId1 + " " + normalId2); //Logging::debug(MString("uvIds ") + uvId0 + " " + uvId1 + " " + uvId2); } } }
MStatus mshUtil::doIt( const MArgList& args ) { MString objname, mcfname; MArgDatabase argData(syntax(), args); MSelectionList selList; MGlobal::getActiveSelectionList ( selList ); if ( selList.length() < 2 ) { MGlobal:: displayError ( "Not sufficient selection!" ); return MS::kSuccess; } MItSelectionList iter( selList ); iter.reset(); MDagPath meshPath; iter.getDagPath( meshPath ); meshPath.extendToShape(); MObject meshObj = meshPath.node(); MString surface = meshPath.partialPathName(); MStatus status; MFnMesh meshFn(meshPath, &status ); if(!status) { MGlobal:: displayError ( "Not sufficient selection!" ); return MS::kSuccess; } MPointArray vxa; meshFn.getPoints (vxa, MSpace::kWorld); MPoint cenfrom(0.f, 0.f, 0.f); for(unsigned i=0; i<vxa.length(); i++) cenfrom += vxa[i]; cenfrom = cenfrom/(float)vxa.length(); iter.next(); iter.getDagPath( meshPath ); meshPath.extendToShape(); MFnMesh mesh1Fn(meshPath, &status ); if(!status) { MGlobal:: displayError ( "Not sufficient selection!" ); return MS::kSuccess; } vxa.clear(); mesh1Fn.getPoints (vxa, MSpace::kWorld); MPoint cento(0.f, 0.f, 0.f); for(unsigned i=0; i<vxa.length(); i++) cento += vxa[i]; cento = cento/(float)vxa.length(); MVector diff = cento - cenfrom; MDoubleArray res; res.append(diff.x); res.append(diff.y); res.append(diff.z); setResult ( res ); /* if ( !argData.isFlagSet("-i") || !argData.isFlagSet("-o") ) { //MGlobal::displayError( "No .obj or .mcf file specified to translate! Example: mshUtil -i filename.obj -o filename.mcf" ); return MS::kSuccess; } else { argData.getFlagArgument("-i", 0, objname); argData.getFlagArgument("-o", 0, mcfname); return MS::kSuccess; } */ return MS::kSuccess; }
// get the mesh informations from the current time and save it in the meshDataList void MayaObject::addMeshData() { MeshData mdata; if (this->hasBifrostVelocityChannel()) { bool doMb = this->motionBlurred; std::shared_ptr<RenderGlobals> renderGlobals = MayaTo::getWorldPtr()->worldRenderGlobalsPtr; doMb = doMb && renderGlobals->doMb; Logging::debug(MString("Found bifrost velocity data for object: ") + this->shortName); if ((this->meshDataList.size() == 2) || !doMb) { Logging::debug("Bifrost mesh already has two motion steps or mb is turned off for it -> skipping"); return; } this->getMeshData(mdata.points, mdata.normals); // if we have a bifrost velocity channel I suppose this is a bifost mesh and there is no need to // save the mesh motion steps because it has changing topology what does not work in most renderers // so we save only the very first motion step and derive the other steps from velocity channel. // and we simply produce two steps only because everything else would not make sense. MFnMesh meshFn(this->mobject); if (meshFn.hasColorChannels("bifrostVelocity")) { MColorArray colors; MString colorSetName = "bifrostVelocity"; meshFn.getVertexColors(colors, &colorSetName); if (colors.length() == mdata.points.length()) { for (uint ptId = 0; ptId < mdata.points.length(); ptId++) { MColor c = colors[ptId]; MVector v = MVector(c.r, c.g, c.b); mdata.points[ptId] -= v * 0.5 / 24.0; } this->meshDataList.push_back(mdata); for (uint ptId = 0; ptId < mdata.points.length(); ptId++) { MColor c = colors[ptId]; MVector v = MVector(c.r, c.g, c.b); mdata.points[ptId] += v * 0.5 / 24.0; } this->meshDataList.push_back(mdata); } }else{ Logging::debug("Bifrost mesh has no velocity data, no motionblur."); if (this->meshDataList.size() == 0) this->meshDataList.push_back(mdata); } } else{ this->getMeshData(mdata.points, mdata.normals); int np = mdata.points.length(); this->meshDataList.push_back(mdata); for (auto md : this->meshDataList) { np = md.points.length(); } } }
// #### rebuildHbrMeshIfNeeded // // If the topology of the mesh changes, or any attributes that affect // how the mesh is computed the original HBR needs to be rebuilt // which will trigger a rebuild of the FAR mesh and subsequent buffers. // void OsdMeshData::rebuildHbrMeshIfNeeded(OpenSubdivShader *shader) { MStatus status = MS::kSuccess; if (!_meshTopoDirty && !shader->getHbrMeshDirty()) return; MFnMesh meshFn(_meshDagPath); // Cache attribute values _level = shader->getLevel(); _kernel = shader->getKernel(); _adaptive = shader->isAdaptive(); _uvSet = shader->getUVSet(); // Get Maya vertex topology and crease data MIntArray vertexCount; MIntArray vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData); if (vertexCount.length() == 0) return; // Copy Maya vectors into std::vectors std::vector<int> numIndices(&vertexCount[0], &vertexCount[vertexCount.length()]); std::vector<int> faceIndices(&vertexList[0], &vertexList[vertexList.length()]); std::vector<int> vtxCreaseIndices(&vtxIds[0], &vtxIds[vtxIds.length()]); std::vector<double> vtxCreases(&vtxCreaseData[0], &vtxCreaseData[vtxCreaseData.length()]); std::vector<double> edgeCreases(&edgeCreaseData[0], &edgeCreaseData[edgeCreaseData.length()]); // Edge crease index is stored as pairs of vertex ids int nEdgeIds = edgeIds.length(); std::vector<int> edgeCreaseIndices; edgeCreaseIndices.resize(nEdgeIds*2); for (int i = 0; i < nEdgeIds; ++i) { int2 vertices; status = meshFn.getEdgeVertices(edgeIds[i], vertices); if (status.error()) { MERROR(status, "OpenSubdivShader: Can't get edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } // Convert attribute enums to HBR enums (this is why the enums need to match) HbrMeshUtil::SchemeType hbrScheme = (HbrMeshUtil::SchemeType) shader->getScheme(); OsdHbrMesh::InterpolateBoundaryMethod hbrInterpBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) shader->getInterpolateBoundary(); OsdHbrMesh::InterpolateBoundaryMethod hbrInterpUVBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) shader->getInterpolateUVBoundary(); // clear any existing face-varying descriptor if (_fvarDesc) { delete _fvarDesc; _fvarDesc = NULL; } // read UV data from maya and build per-face per-vert list of UVs for HBR face-varying data std::vector< float > uvList; status = buildUVList( meshFn, uvList ); if (! status.error()) { // Create face-varying data descriptor. The memory required for indices // and widths needs to stay alive as the HBR library only takes in the // pointers and assumes the client will maintain the memory so keep _fvarDesc // around as long as _hbrmesh is around. int fvarIndices[] = { 0, 1 }; int fvarWidths[] = { 1, 1 }; _fvarDesc = new FVarDataDesc( 2, fvarIndices, fvarWidths, 2, hbrInterpUVBoundary ); } if (_fvarDesc && hbrScheme != HbrMeshUtil::kCatmark) { MGlobal::displayWarning("Face-varying not yet supported for Loop/Bilinear, using Catmull-Clark"); hbrScheme = HbrMeshUtil::kCatmark; } // Convert Maya mesh to internal HBR representation _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, hbrInterpBoundary, hbrScheme, false, // no ptex _fvarDesc, _fvarDesc?&uvList:NULL); // yes fvar (if have UVs) // note: GL function can't be used in prepareForDraw API. _needsInitializeMesh = true; // Mesh topology data is up to date _meshTopoDirty = false; shader->setHbrMeshDirty(false); }