最近希望将MeshLab的ply模型转化为Ogre的mesh模型,最初的思路是:
(1)在MeshLab中将ply模型转化为Maya支持的obj模型;
(2)利用插件,在Maya中将obj模型导出为mesh模型。
上述思路是可行的,但导出后发现虽然面片数目没变,但顶点数目增加了很多。由于精确控制到每个顶点,故这样的导出是没有价值的。经过再三考虑,我决定自己写一个小程序,能将ply直接转化为mesh。
我首先实现的是将只有顶点(vertex)和索引(index)的ply数据导出为mesh模型。
代码如下:
/* * File: CxMesh.h * Author: zhuxiaoyang ([email protected]) * * Created on July 25th, 2011, PM 7:00 */ #ifndef __CxMesh_H__ #define __CxMesh_H__ #include <Ogre.h> #include <fstream> using namespace Ogre; using namespace std; class CxMesh { private: MeshPtr mesh; SubMesh *subMesh; String meshName; int numFaces; int numVertices; float* vertices; int* faces; HardwareVertexBufferSharedPtr posVertexBuffer; HardwareIndexBufferSharedPtr indexBuffer; public: CxMesh(const String& meshName); virtual ~CxMesh(); // Read and write ply file bool cxReadPly(const String fileName); }; #endif // __CxMesh_H__
#include "CxMesh.h" CxMesh::CxMesh(const String& meshName) { this->meshName = meshName; numFaces = 0; numVertices = 0; vertices = NULL; } CxMesh::~CxMesh() { if(vertices) delete[] vertices; MeshManager::getSingleton().remove(meshName); } bool CxMesh::cxReadPly(const String fileName) { // Open the .ply file for reading ifstream fin( fileName.c_str() ); if(!fin) { String errMsg = "//** Error opening ply file for input!"; Ogre::LogManager::getSingleton().logMessage(errMsg); return false; } // Analysing the file String plyStr; while( getline(fin, plyStr) ) { if(plyStr == "end_header") break; if( plyStr.substr(0, 7) == "element" ) { if( plyStr.substr(8, 6) == "vertex" ) numVertices = atoi( plyStr.substr(15,8).c_str() ); //** the length of the substr may change else if(plyStr.substr(8, 4) == "face") numFaces = atoi( plyStr.substr(13,8).c_str() ); } } // Read vertex data from the file vertices = new float[numVertices*3]; for(int i = 0; i < numVertices; ++i) { fin>>vertices[i * 3 + 0] >>vertices[i * 3 + 1] >>vertices[i * 3 + 2]; } // Read face data from the file faces = new int[numFaces*3]; int temp; for(int i = 0; i < numFaces; ++i) { fin>>temp>>faces[i * 3 + 0] >>faces[i * 3 + 1] >>faces[i * 3 + 2]; } // Close the file fin.close(); // Create mesh and submesh mesh = MeshManager::getSingleton().createManual(meshName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); subMesh = mesh->createSubMesh(); // Vertex Buffer mesh->sharedVertexData = new VertexData(); mesh->sharedVertexData->vertexCount = numVertices; VertexDeclaration* vdecl = mesh->sharedVertexData->vertexDeclaration; VertexBufferBinding* vbind = mesh->sharedVertexData->vertexBufferBinding; vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION); // Prepare buffer for positions posVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 3*sizeof(float), numVertices, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE); posVertexBuffer->writeData(0, posVertexBuffer->getSizeInBytes(), vertices, true); vbind->setBinding(0, posVertexBuffer); // Prepare buffer for indices indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( HardwareIndexBuffer::IT_32BIT, 3*numFaces, HardwareBuffer::HBU_STATIC, true); // Upload the index data to the card indexBuffer->writeData(0, indexBuffer->getSizeInBytes(), faces, true); // Set parameters of the submesh subMesh->useSharedVertices = true; subMesh->indexData->indexBuffer = indexBuffer; subMesh->indexData->indexStart = 0; subMesh->indexData->indexCount = 3*numFaces; mesh->_setBounds( AxisAlignedBox(-100, -100, -100, 100, 100, 100) ); // Notify -Mesh object that it has been loaded mesh->load(); mesh->touch(); Ogre::StringStream ss; ss<<setprecision(10)<<"//** The vertex count is "<<numVertices <<" ** the index count is " <<numFaces <<"The first vertex is "<<vertices[0]<<" "<<vertices[1]<<" "<<vertices[2] <<"**The last vertex is"<<vertices[(numVertices-1)*3+0]<<" " <<vertices[(numVertices-1)*3+1]<<" "<<vertices[(numVertices-1)*3+2] <<"The first face is "<<faces[0]<<" "<<faces[1]<<" "<<faces[2] <<"**The last vertex is"<<faces[(numFaces-1)*3+0]<<" " <<faces[(numFaces-1)*3+1]<<" "<<faces[(numFaces-1)*3+2]; Ogre::LogManager::getSingleton().logMessage( ss.str() ); return true; }程序运行时,可调用如下代码:
//** Read a .ply file and convert it to mesh String meshMocap = "meshMocap"; CxMesh mMocap = new CxMesh( meshMocap ); mMocap->cxReadPly("mocap.ply"); // Add a model to the scene Ogre::SceneNode* mModelNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("ModelNode"); Ogre::Entity* mModel = mSceneMgr->createEntity("MyModel", meshMocap); mModelNode->attachObject(mModel); mModelNode->scale(0.5, 0.5, 0.5);这样就可以在程序中看到模型了。