1、计算机图形学实验报告2计算机图形学实验报告实验二、 三维网格模型光顺一、实验目的与基本要求:(1)掌握Obj文件的读入;(2)利用给定的数据结构类,建立读入网格模型数据结构;(3)利用OpenGL类库,对三维模型进行绘制;(4)利用OpenGL类库,增加采用鼠标交互方式对三维模型进行旋转、放缩、平移等操作;(5)实现Laplacian方法的三维模型光顺操作,并观察三维模型光顺过程;二、实验设备(环境)及要求1. 操作系统:Windows XP 或 Windows 72. 编程环境:Microsoft Visual Studio 2010,OpenGL 库函数3. 界面框架:Win32,MFC,
2、QT选择其中一种三、实验内容与步骤实验分为以下几个步骤:(1)掌握Obj文件的读入顶点和面的个数;(2)建立数组存储点的坐标及面上的点数;(3)存储顶点的邻接面数,并记录每个顶点周围的邻接点(4)计算每个面的法向利用OpenGL类库,增加采用鼠标交互方式对三维模型进行旋转、放缩、平移等操作;(5)利用面法向及顶点坐标进行绘制几何体(6)实现鼠标对物体旋转、平移、缩放的算法(7)实现Laplacian方法的三维模型光顺操作,并观察三维模型光顺过程;4、实现过程说明及成果展示:(1)掌握Obj文件的读入顶点和面的个数;由于obj文件的存储形式是v x1 x2 x3;f v1 v2 v3;这种形式,
3、所以在记录点和面的数量时,只需按行读取,然后再判断首字母是v/f即可实现代码如下:(2)建立数组存储点的坐标及面上的点数;数组的大小由点数和面数决定,点数组和面数组均由0开始记录,故后面再用面对应点的时候,由于面上点是从1开始记录,故需要减1然后使用,代码如下:(3)存储顶点的邻接面数,并记录每个顶点周围的邻接点记录点邻接面的是新建一个数组,在读面的时候,将该面的序号存入对应点的数组中,然后再在每个面上取一点,记录到点的邻接点数组中,在每个面上取得的点为向外右手方向的下一个点,实现代码如下:(4)计算每个面的法向计算面的法向方式为面上右手方向上的两向量的叉乘得到,即所用代码为:(8)利用面法向
4、及顶点坐标进行绘制几何体用法向绘制的方式是先用glNormal3fv(v)指出面的法向;再用glVertex3f传入面上点的坐标;由于我将glNormal3fv(v)中写在算法向所以我直接对此直接调用即可,代码如下:(9)实现鼠标对物体旋转、平移、缩放的算法平移:利用Transform函数和键盘事件来改变参数,w,s,a,d分别控制绘制的kitty猫的上下左右的移动:实现代码如下:旋转:利用gllookat();函数设定了观察角度,并用鼠标事件改变参数,用实现观察视角的变化实现物体的旋转,代码如下:缩放:运用glScalef方法和键盘事件改变参数,实现物体的放大和缩小,代码如下:(10)实现L
5、aplacian方法的三维模型光顺操作,并观察三维模型光顺过程;Laplacian方法的原理是利用目标点与其所有邻接点平均后的点的差向量,对目标点的坐标进行变换的过程,具体方法是:建立每个点的邻接顶点数组,存储每个点的邻接点对每个顶点的邻接点进行求平均,即将邻接点的坐标求和后除以邻接点个数,从而得到邻接平均点得到优化向量优化向量 = 邻接平均点 - 目标点设定优化度参数,得到优化后的新坐标新坐标 = 目标点 + *优化向量在程序中,对于第num个顶点,我设定的变量为目标点vArr邻接平均点v0优化向量l新坐标数组vNewArr具体代码如下:5、结果展示及说明计算面法向后直接绘制(未光顺):光顺
6、进行一次后光顺多次后利用点绘制结果为旋转后缩放后平移后6、心得体会(1)计算面法向时法向量的方向没有运用右手方向,导致有的面法向向里,从而出现雪花(2)在运用Laplacian算法进行求邻接平均点时未初始化邻接平均点数组,导致平均点的累加从而出现越光顺越粗糙的现象(3)在obj文件中面对应顶点数和顶点数组的标号相差1.在运用的时候需减1,面从1开始记顶点,顶点数组从0开始记顶点7、实验代码#defineGLUT_DISABLE_ATEXIT_HACK#include#include#include#include#include#include#include#include#includeu
7、singnamespace std;int v_num = 0; /记录点的数量int f_num = 0; /记录面的数量int vn_num = 0;/记录法向量的数量int vt_num = 0;GLfloat *vArr; /存放点的二维数组GLfloat *vNewArr;/存放点的二维数组int *fvArr; /存放面顶点的二维数组GLfloat *fnArr;/存放面法向量的二维数组int *ftArr;int *vfArr;/存放顶点临接的面数的数组int *nextVArr;/存放下一个临界顶点的数组GLfloat *vnArr;/存放点法向量的二维数组string s1,
8、 s2, s3, s4;GLfloat f2, f3, f4;int num1, num2, num3;typedefGLfloatpoint33;point3 x, y,l;/平面上的两个向量x,y和拉普拉斯向量lstaticGLfloat theta = 0.0,0.0,0.0 ;staticGLint axis = 2;staticGLdouble viewer = 0.0, 0.0, 5.0 ; /* initial viewer location */staticGLdouble Tran = 0.0,0.0,0.0 ;staticGLdouble sca = 1.0;void ge
9、tLineNum(stringaddrstr) /获取点和面的数量 ifstream infile(addrstr.c_str(); /打开指定文件 if (!infile) cout open error! endl; exit(1); string sline;/每一行 int i = 0, j = 0; while (getline(infile, sline) /从指定文件逐行读取 if (sline0 = v) v_num+; if (sline0 = f) f_num+; int readfile(stringaddrstr) /将文件内容读到数组中去 /getLineNum(ad
10、drstr); /new二维数组 vArr = newGLfloat*v_num; for (int i = 0; i v_num; i+) vArri = newGLfloat3; vNewArr = newGLfloat*v_num; for (int i = 0; i v_num; i+) vNewArri = newGLfloat3; vnArr = newGLfloat*vn_num; for (int i = 0; i vn_num; i+) vnArri = newGLfloat3; vfArr = newint*v_num; for (int i = 0; i v_num; i
11、+) vfArri = newint10; for (int j = 0; j 10; j+) vfArrij = -1; nextVArr = newint*v_num; for (int i = 0; i v_num; i+) nextVArri = newint10; for (int j = 0; j 10; j+) nextVArrij = -1; fvArr = newint*f_num; fnArr = newGLfloat*f_num; ftArr = newint*f_num; for (int i = 0; i f_num; i+) fvArri = newint3; fn
12、Arri = newGLfloat3; ftArri = newint10; ifstream infile(addrstr.c_str(); if (!infile) cout open error! s1 f2 f3 f4; vArrii0 = f2; vArrii1 = f3; vArrii2 = f4; ii+; if (sline0 = f) /存储面 istringstream in(sline); GLfloat a; in s1num1num2num3;/去掉f fvArrkk0 = num1; fvArrkk1 = num2; fvArrkk2 = num3; for (in
13、t i = 0; i 10; i+) if (vfArrnum1-1i = -1) vfArrnum1-1i = kk; nextVArrnum1-1i = num2; break; for (int j = 0; j 10; j+) if (vfArrnum2-1j = -1) vfArrnum2-1j = kk; nextVArrnum2-1j = num3; break; for (int i = 0; i 10; i+) if (vfArrnum3-1i = -1) vfArrnum3-1i = kk; nextVArrnum3-1i = num1; break; kk+; retur
14、n 0;/计算面法向void nomal(point3p) /*矢量的归一化*/ /double sqrt(); float d = 0.0; int i; for (i = 0; i 0.0) for (i = 0; i 3; i+) pi /= d;void getFaceNormal(point3A, point3B, point3C) x0 = C0 - A0; x1 = C1 - A1; x2 = C2 - A2; y0 = A0 - B0; y1 = A1 - B1; y2 = A2 - B2; point3 v; v0 = x1 * y2 - x2 * y1; v1 = x2 *
15、 y0 - x0 * y2; v2 = x0 * y1 - x1 * y0; nomal(v); glNormal3fv(v);void Laplacian() for (int num = 0; num v_num; num+) int m = 0; /求得点的邻接面数 for (int i = 0; i 10; i+) if (nextVArrnumi != -1) m+; else break; point3 v0; for (int i = 0; i 3; i+) v0i = 0; for (int i = 0; i m; i+) v00 += vArrnextVArrnumi - 1
16、0; v01 += vArrnextVArrnumi - 11; v02 += vArrnextVArrnumi - 12; if (m != 0) for (int i = 0; i 3; i+) v0i /= m; l0 = v00 - vArrnum0; l1 = v01 - vArrnum1; l2 = v02 - vArrnum2; vNewArrnum0 = vArrnum0 + l0 * 0.3; vNewArrnum1 = vArrnum1 + l1 * 0.3; vNewArrnum2 = vArrnum2 + l2 * 0.3; for (int i = 0; i v_nu
17、m; i+) vArri0 = vNewArri0; vArri1 = vNewArri1; vArri2 = vNewArri2; void init(void) getLineNum(H:kitten_noisy.obj); readfile(H:kitten_noisy.obj); double viewer = 0.0, 0.0, 8.0 ; /* initial viewer location */ GLfloat mat_specular = 1.0, 1.0, 1.0, 1.0 ; GLfloat mat_shininess = 50.0 ;/材料的镜面指数,其值越大越精细 GL
18、float light_position = 1.0, 1.0f, 1.0, 0.0 ; GLfloat white_light = 1.0, 1.0, 1.0, 1.0 ; GLfloat lmodel_ambient = 0.1, 0.1, 0.1, 1.0 ; glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glL
19、ightfv(GL_LIGHT0, GL_POSITION, light_position);/光源位置 glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);/漫反射光源 glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);/镜面反射光源 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);/环境光源/ glEnable(glMaterialf); glEnable(GL_LIGHTING);/启动光照 glEnable(GL_LIGHT0);/启用0度光
20、源 glEnable(GL_DEPTH_TEST);/启动深度测试 /* glShadeModel(GL_SMOOTH); / Enable Smooth Shading glClearColor(0.0f, 0.0f, 0.0f, 0.5f); / 黑色背景 glClearDepth(1.0f); / 深度缓冲区设置 glEnable(GL_DEPTH_TEST); / 允许深度测试 glDepthFunc(GL_LEQUAL); / 定义深度测试类型 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); / Really Nice Persp
21、ective Calculation */void display(void) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(viewer0, viewer1, viewer2, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); /设置观察的位置 glRotatef(theta0, 1.0, 0.0, 0.0); glRotatef(theta1, 0.0, 1.0, 0.0); /glRotatef(theta2, 0.0, 0.0, 1.0); glTranslat
22、ef(Tran0, Tran1, Tran2); glScalef(sca, sca, sca); /glPolygonMode(GL_FRONT_AND_BACK, GLU_FILL); glBegin(GL_TRIANGLES); /getFaceNormals(); for (int i = 0; if_num; i+) getFaceNormal(vArrfvArri0 - 1, vArrfvArri1 - 1, vArrfvArri2 - 1); glVertex3f(vArrfvArri0 - 10, vArrfvArri0 - 11, vArrfvArri0 - 12); glV
23、ertex3f(vArrfvArri1 - 10, vArrfvArri1 - 11, vArrfvArri1 - 12); glVertex3f(vArrfvArri2 - 10, vArrfvArri2 - 11, vArrfvArri2 - 12); glEnd(); /* glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glBegin(GL_POINTS); glColor3f(1.0, 1.0, 1.0); for (int i = 0; i v_num; i+) glVertex3fv(vArri); glNormal3fv(fnArri); glEnd(); */ glFlush();/强制绘图 glutSwapBuffers();void reshape(intw, inth) glViewport(0, 0, (GLsizei)w, (GLsizei)h); /视口设置 glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w 360.0) thetaaxis -= 360.0; display();void keys(unsignedcharkey, intx, inty) if (key = a) Tran0 -= 0.2; i
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1