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文件的。
三张图分别是显示面,点,线的,当然任意多少种元素一起显示也是可以的。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容