OpenMesh學習筆記5 OpenMesh+OpenGL的一個例子


OpenMesh+OpenGL的一個例子

    這篇文章主要給一個OpenMesh的例子,其中Mesh數據是從文件中讀取的,關於OpenMesh中的Mesh IO,會在后面的博文中給出,這部分代碼可以忽略,反正需要知道的就是,經過IO之后,數據就存在一個MyMesh mesh變量中了。然后重點可以看一下其中的點,線,面是怎么遍歷的,還有就是點的三維坐標是怎么通過函數返回的。下面直接上代碼,后面再做一點簡單分析。
#include <iostream>
//// ------------------- OpenMesh
#include <OpenMesh\Core\IO\MeshIO.hh>
#include <OpenMesh\Core\Mesh\TriMesh_ArrayKernelT.hh>

//// --------------------OpenGL
#include <GL\freeglut.h>

using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;

MyMesh mesh;
//
float xRotate = 0.0f;
float yRotate = 0.0f;
float zRotate = 0.0f;
float scale = 1.0;
GLuint showFaceList, showWireList, showPointList;

bool showFace = true;
bool showWire = false;
bool showPoint = false;
//
void initGL()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
// ------------------- Lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
// ------------------- Display List
showFaceList = glGenLists(1);
showWireList = glGenLists(1);
showPointList = glGenLists(1);
int temp = mesh.n_edges();
// SHOW WIRE
glNewList(showWireList, GL_COMPILE);
glDisable(GL_LIGHTING);
glLineWidth(1.0f);
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_LINES);
for (MyMesh::HalfedgeIter he_it = mesh.halfedges_begin(); he_it != mesh.halfedges_end(); ++he_it) {
glVertex3fv(mesh.point(mesh.from_vertex_handle(*he_it)).data());
glVertex3fv(mesh.point(mesh.to_vertex_handle(*he_it)).data());
}
glEnd();
glEnable(GL_LIGHTING);
glEndList();
// SHOW POINT
glNewList(showPointList, GL_COMPILE);
glDisable(GL_LIGHTING);
glLineWidth(1.0f);
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_POINTS);
for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) {
glVertex3fv(mesh.point(*v_it).data());
}
glEnd();
glEnable(GL_LIGHTING);
glEndList();
// SHOW FACE
glNewList(showFaceList, GL_COMPILE);
for (MyMesh::FaceIter f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
glBegin(GL_TRIANGLES);
for (MyMesh::FaceVertexIter fv_it = mesh.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) {
glNormal3fv(mesh.normal(*fv_it).data());
glVertex3fv(mesh.point(*fv_it).data());
//glVertex3f(mesh.point(*fv_it)[0], mesh.point(*fv_it)[1], mesh.point(*fv_it)[2]);
}
glEnd();
}
glEndList();
}
//
void myReshape(GLint w, GLint h)
{
glViewport(0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w > h)
glOrtho(-static_cast<GLdouble>(w) / h, static_cast<GLdouble>(w) / h, -1.0, 1.0, -1.0, 1.0);
else
glOrtho(-1.0, 1.0, -static_cast<GLdouble>(h) / w, static_cast<GLdouble>(h) / w, -1.0, 1.0);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//
void myIdle()
{
xRotate += 0.5f;
yRotate += 1.0f;
zRotate += 1.5f;
if (xRotate >= 360.0f)
xRotate -= 360.0f;
if (yRotate >= 360.0f)
yRotate -= 360.0f;
if (zRotate >= 360.0f)
zRotate -= 360.0f;
glutPostRedisplay();
}
//
void mySpecial(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP:
xRotate += 5.0f;
break;
case GLUT_KEY_DOWN:
xRotate -= 5.0f;
break;
case GLUT_KEY_LEFT:
yRotate += 5.0f;
break;
case GLUT_KEY_RIGHT:
yRotate -= 5.0f;
break;
case GLUT_KEY_PAGE_UP:
scale = scale + 0.02;
break;
case GLUT_KEY_PAGE_DOWN:
scale = scale - 0.02;
break;
default:
break;
}
glutPostRedisplay();
}
//
void myKeyboard(unsigned char key, int x, int y)
{
switch (key) {
case '1':
showFace = !showFace;
break;
case '2':
showPoint = !showWire;
break;
case '3':
showWire = !showPoint;
break;
default:
break;
}
glutPostRedisplay();
}
//
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(xRotate, 1.0f, 0.0f, 0.0f);
glRotatef(yRotate, 0.0f, 1.0f, 0.0f);
glRotatef(zRotate, 0.0f, 0.0f, 1.0f);
glScalef(scale, scale, scale);

if (showFace)
glCallList(showFaceList);
if (showPoint)
glCallList(showPointList);
if (showWire)
glCallList(showWireList);
glutSwapBuffers();
}



int main(int argc, char** argv)
{
// request vertex normals, so the mesh reader can use normal information
// if available
mesh.request_vertex_normals();
// assure we have vertex normals
if (!mesh.has_vertex_normals())
{
std::cerr << "ERROR: Standard vertex property 'Normals' not available!\n";
return 1;
}
// Read mesh
OpenMesh::IO::Options opt;
const char* filename = "off/23.off";
if (!OpenMesh::IO::read_mesh(mesh, filename, opt))
{
cerr << "Error: Cannot read mesh from " << filename << endl;
return 1;
}
// If the file did not provide vertex normals, then calculate them
if (!opt.check(OpenMesh::IO::Options::VertexNormal))
{
// we need face normals to update the vertex normals
mesh.request_face_normals();

// let the mesh update the normals
mesh.update_normals();

// dispose the face normals, as we don't need them anymore
mesh.release_face_normals();
}
// write mesh to output.obj
try
{
if (!OpenMesh::IO::write_mesh(mesh, "output.obj"))
{
std::cerr << "Cannot write mesh to file 'output.obj'" << std::endl;
return 1;
}
}
catch (std::exception& x)
{
std::cerr << x.what() << std::endl;
return 1;
}

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(800, 500);
glutCreateWindow("Mesh Viewer");
initGL();
glutKeyboardFunc(&myKeyboard);
glutSpecialFunc(&mySpecial);
glutReshapeFunc(&myReshape);
glutDisplayFunc(&myDisplay);
glutMainLoop();
return 0;
}
    上面的大部分代碼都是用於搭建Opengl環境用的,比如設置一些消息處理函數等。對於mesh的操作,主要要了解的有以下幾處:
    1,文件讀寫,這個日后介紹,OpenMesh已經封裝了讀寫off,obj,ply等文件的功能,並且會存儲成半邊結構;
    2,法向計算,我所讀的這個文件里,是沒有法向的,以為在后面渲染時要用到法向,所以先計算了法向,這部分也日后介紹;
    3,邊,點,面的遍歷,也就是上一節介紹的迭代器和循環器。例如顯示點的時候,只需要用迭代器就可以了,得到每個點的坐標就行了,得到點的坐標是通過.data()函數實現的,返回的剛好是3維的數組,剛好對應上了opengl函數中的--3*v函數,然后關於邊和面就要同時用到迭代器和循環器了,在initGL可以看到,我這里用了3個顯示列表,這是OpenGL中的一個功能吧,目的是讓程序在渲染的時候快點,程序運行中,可以通過方向鍵控制模型旋轉,PageUp和PageDown控制模型縮放,然后1,2,3控制顯示的元素(點,線,面);
    好了,下面就上運行的一個結果,其中的off文件是我從網上下的,是Mesh Segmentation Benchmark網站上下的,百度下就有,里面有300個off文件的。


    三張圖分別是顯示面,點,線的,當然任意多少種元素一起顯示也是可以的。
   

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com