计算机图形学实验报告2.docx
- 文档编号:4725068
- 上传时间:2022-12-08
- 格式:DOCX
- 页数:27
- 大小:1.79MB
计算机图形学实验报告2.docx
《计算机图形学实验报告2.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验报告2.docx(27页珍藏版)》请在冰豆网上搜索。
计算机图形学实验报告2
计算机图形学实验报告
实验二、三维网格模型光顺
一、实验目的与基本要求:
(1)掌握Obj文件的读入;
(2)利用给定的数据结构类,建立读入网格模型数据结构;
(3)利用OpenGL类库,对三维模型进行绘制;
(4)利用OpenGL类库,增加采用鼠标交互方式对三维模型进行旋转、放缩、平移等操作;
(5)实现Laplacian方法的三维模型光顺操作,并观察三维模型光顺过程;
二、实验设备(环境)及要求
1.操作系统:
WindowsXP或Windows7
2.编程环境:
MicrosoftVisualStudio2010,OpenGL库函数
3.界面框架:
Win32,MFC,QT选择其中一种
三、实验内容与步骤
实验分为以下几个步骤:
(1)掌握Obj文件的读入顶点和面的个数;
(2)建立数组存储点的坐标及面上的点数;
(3)存储顶点的邻接面数,并记录每个顶点周围的邻接点
(4)计算每个面的法向
利用OpenGL类库,增加采用鼠标交互方式对三维模型进行旋转、放缩、平移等操作;
(5)利用面法向及顶点坐标进行绘制几何体
(6)实现鼠标对物体旋转、平移、缩放的算法
(7)实现Laplacian方法的三维模型光顺操作,并观察三维模型光顺过程;
4、实现过程说明及成果展示:
(1)掌握Obj文件的读入顶点和面的个数;
由于obj文件的存储形式是
vx1x2x3;
…
fv1v2v3;
…
这种形式,所以在记录点和面的数量时,只需按行读取,然后再判断首字母是v/f即可
实现代码如下:
(2)建立数组存储点的坐标及面上的点数;
数组的大小由点数和面数决定,点数组和面数组均由0开始记录,故后面再用面对应点的时候,由于面上点是从1开始记录,故需要减1然后使用,代码如下:
(3)存储顶点的邻接面数,并记录每个顶点周围的邻接点
记录点邻接面的是新建一个数组,在读面的时候,将该面的序号存入对应点的数组中,然后再在每个面上取一点,记录到点的邻接点数组中,在每个面上取得的点为向外右手方向的下一个点,实现代码如下:
(4)计算每个面的法向
计算面的法向方式为面上右手方向上的两向量的叉乘得到,即
所用代码为:
(8)利用面法向及顶点坐标进行绘制几何体
用法向绘制的方式是
先用glNormal3fv(v)指出面的法向;再用glVertex3f传入面上点的坐标;由于我将glNormal3fv(v)中写在算法向所以我直接对此直接调用即可,代码如下:
(9)实现鼠标对物体旋转、平移、缩放的算法
平移:
利用Transform函数和键盘事件来改变参数,w,s,a,d分别控制绘制的kitty猫的上下左右的移动:
实现代码如下:
旋转:
利用gllookat();函数设定了观察角度,并用鼠标事件改变参数,用实现观察视角的变化实现物体的旋转,代码如下:
缩放:
运用glScalef方法和键盘事件改变参数,实现物体的放大和缩小,代码如下:
(10)实现Laplacian方法的三维模型光顺操作,并观察三维模型光顺过程;
Laplacian方法的原理是利用目标点与其所有邻接点平均后的点的差向量,对目标点的坐标进行变换的过程,具体方法是:
①建立每个点的邻接顶点数组,存储每个点的邻接点
②对每个顶点的邻接点进行求平均,即将邻接点的坐标求和后除以邻接点个数,从而得到邻接平均点
③得到优化向量
优化向量=邻接平均点-目标点
④设定优化度参数λ,得到优化后的新坐标
新坐标=目标点+λ*优化向量
在程序中,对于第num个顶点,我设定的变量为
目标点vArr
邻接平均点v0
优化向量l
新坐标数组vNewArr
具体代码如下:
5、结果展示及说明
计算面法向后直接绘制(未光顺):
光顺进行一次后
光顺多次后
利用点绘制结果为
旋转后
缩放后
平移后
6、心得体会
(1)计算面法向时法向量的方向没有运用右手方向,导致有的面法向向里,从而出现雪花
(2)在运用Laplacian算法进行求邻接平均点时未初始化邻接平均点数组,导致平均点的累加
从而出现越光顺越粗糙的现象
(3)在obj文件中面对应顶点数和顶点数组的标号相差1.在运用的时候需减1,面从1开始记顶点,顶点数组从0开始记顶点
7、实验代码
#defineGLUT_DISABLE_ATEXIT_HACK
#include
#include
#include
#include
#include
#include
#include
#include
#include
usingnamespacestd;
intv_num=0;//记录点的数量
intf_num=0;//记录面的数量
intvn_num=0;//记录法向量的数量
intvt_num=0;
GLfloat**vArr;//存放点的二维数组
GLfloat**vNewArr;//存放点的二维数组
int**fvArr;//存放面顶点的二维数组
GLfloat**fnArr;//存放面法向量的二维数组
int**ftArr;
int**vfArr;//存放顶点临接的面数的数组
int**nextVArr;//存放下一个临界顶点的数组
GLfloat**vnArr;//存放点法向量的二维数组
strings1,s2,s3,s4;
GLfloatf2,f3,f4;
intnum1,num2,num3;
typedefGLfloatpoint3[3];
point3x,y,l;//平面上的两个向量x,y和拉普拉斯向量l
staticGLfloattheta[]={0.0,0.0,0.0};
staticGLintaxis=2;
staticGLdoubleviewer[]={0.0,0.0,5.0};/*initialviewerlocation*/
staticGLdoubleTran[]={0.0,0.0,0.0};
staticGLdoublesca=1.0;
voidgetLineNum(stringaddrstr)//获取点和面的数量
{
ifstreaminfile(addrstr.c_str());//打开指定文件
if(!
infile){
cout<<"openerror!
"< exit (1); } stringsline;//每一行 inti=0,j=0; while(getline(infile,sline))//从指定文件逐行读取 { if(sline[0]=='v') { v_num++; } if(sline[0]=='f') { f_num++; } } } intreadfile(stringaddrstr)//将文件内容读到数组中去 { //getLineNum(addrstr); //new二维数组 vArr=newGLfloat*[v_num]; for(inti=0;i { vArr[i]=newGLfloat[3]; } vNewArr=newGLfloat*[v_num]; for(inti=0;i { vNewArr[i]=newGLfloat[3]; } vnArr=newGLfloat*[vn_num]; for(inti=0;i { vnArr[i]=newGLfloat[3]; } vfArr=newint*[v_num]; for(inti=0;i { vfArr[i]=newint[10]; for(intj=0;j<10;j++){ vfArr[i][j]=-1; } } nextVArr=newint*[v_num]; for(inti=0;i { nextVArr[i]=newint[10]; for(intj=0;j<10;j++){ nextVArr[i][j]=-1; } } fvArr=newint*[f_num]; fnArr=newGLfloat*[f_num]; ftArr=newint*[f_num]; for(inti=0;i { fvArr[i]=newint[3]; fnArr[i]=newGLfloat[3]; ftArr[i]=newint[10]; } ifstreaminfile(addrstr.c_str()); if(! infile){ cout<<"openerror! "< exit (1); } stringsline;//每一行 intii=0,jj=0,kk=0,mm=0; while(getline(infile,sline)) { if(sline[0]=='v')//存储点 { istringstreamsin(sline); sin>>s1>>f2>>f3>>f4; vArr[ii][0]=f2; vArr[ii][1]=f3; vArr[ii][2]=f4; ii++; } if(sline[0]=='f')//存储面 { istringstreamin(sline); GLfloata; in>>s1>>num1>>num2>>num3;//去掉f fvArr[kk][0]=num1; fvArr[kk][1]=num2; fvArr[kk][2]=num3; for(inti=0;i<10;i++){ if(vfArr[num1-1][i]==-1){ vfArr[num1-1][i]=kk; nextVArr[num1-1][i]=num2; break; } } for(intj=0;j<10;j++){ if(vfArr[num2-1][j]==-1){ vfArr[num2-1][j]=kk; nextVArr[num2-1][j]=num3; break; } } for(inti=0;i<10;i++){ if(vfArr[num3-1][i]==-1){ vfArr[num3-1][i]=kk; nextVArr[num3-1][i]=num1; break; } } kk++; } } return0; } //计算面法向 voidnomal(point3p){ /*矢量的归一化*/ //doublesqrt(); floatd=0.0; inti; for(i=0;i<3;i++) d+=p[i]*p[i]; d=sqrt(d); if(d>0.0) for(i=0;i<3;i++) p[i]/=d; } voidgetFaceNormal(point3A,point3B,point3C){ x[0]=C[0]-A[0]; x[1]=C[1]-A[1]; x[2]=C[2]-A[2]; y[0]=A[0]-B[0]; y[1]=A[1]-B[1]; y[2]=A[2]-B[2]; point3v; v[0]=x[1]*y[2]-x[2]*y[1]; v[1]=x[2]*y[0]-x[0]*y[2]; v[2]=x[0]*y[1]-x[1]*y[0]; nomal(v); glNormal3fv(v); } voidLaplacian(){ for(intnum=0;num intm=0; //求得点的邻接面数 for(inti=0;i<10;i++){ if(nextVArr[num][i]! =-1){ m++; } else{ break; } } point3v0; for(inti=0;i<3;i++){ v0[i]=0; } for(inti=0;i v0[0]+=vArr[nextVArr[num][i]-1][0]; v0[1]+=vArr[nextVArr[num][i]-1][1]; v0[2]+=vArr[nextVArr[num][i]-1][2]; } if(m! =0){ for(inti=0;i<3;i++) v0[i]/=m; } l[0]=v0[0]-vArr[num][0]; l[1]=v0[1]-vArr[num][1]; l[2]=v0[2]-vArr[num][2]; vNewArr[num][0]=vArr[num][0]+l[0]*0.3; vNewArr[num][1]=vArr[num][1]+l[1]*0.3; vNewArr[num][2]=vArr[num][2]+l[2]*0.3; } for(inti=0;i vArr[i][0]=vNewArr[i][0]; vArr[i][1]=vNewArr[i][1]; vArr[i][2]=vNewArr[i][2]; } } voidinit(void) { getLineNum("H: \\kitten_noisy.obj"); readfile("H: \\kitten_noisy.obj"); doubleviewer[]={0.0,0.0,8.0};/*initialviewerlocation*/ GLfloatmat_specular[]={1.0,1.0,1.0,1.0}; GLfloatmat_shininess[]={50.0};//材料的镜面指数,其值越大越精细 GLfloatlight_position[]={1.0,1.0f,1.0,0.0}; GLfloatwhite_light[]={1.0,1.0,1.0,1.0}; GLfloatlmodel_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); glLightfv(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度光源 glEnable(GL_DEPTH_TEST);//启动深度测试 /* glShadeModel(GL_SMOOTH);//EnableSmoothShading 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);//ReallyNicePerspectiveCalculation */ } voiddisplay(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(viewer[0],viewer[1],viewer[2],0.0,0.0,0.0,0.0,1.0,0.0);//设置观察的位置 glRotatef(theta[0],1.0,0.0,0.0); glRotatef(theta[1],0.0,1.0,0.0); //glRotatef(theta[2],0.0,0.0,1.0); glTranslatef(Tran[0],Tran[1],Tran[2]); glScalef(sca,sca,sca); //glPolygonMode(GL_FRONT_AND_BACK,GLU_FILL); glBegin(GL_TRIANGLES); //getFaceNormals(); for(inti=0;i { getFaceNormal(vArr[fvArr[i][0]-1],vArr[fvArr[i][1]-1],vArr[fvArr[i][2]-1]); glVertex3f(vArr[fvArr[i][0]-1][0],vArr[fvArr[i][0]-1][1],vArr[fvArr[i][0]-1][2]); glVertex3f(vArr[fvArr[i][1]-1][0],vArr[fvArr[i][1]-1][1],vArr[fvArr[i][1]-1][2]); glVertex3f(vArr[fvArr[i][2]-1][0],vArr[fvArr[i][2]-1][1],vArr[fvArr[i][2]-1][2]); } glEnd(); /* glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glBegin(GL_POINTS); glColor3f(1.0,1.0,1.0); for(inti=0;i glVertex3fv(vArr[i]); glNormal3fv(fnArr[i]); } glEnd(); */ glFlush();//强制绘图 glutSwapBuffers(); } voidreshape(intw,inth) { glViewport(0,0,(GLsizei)w,(GLsizei)h);//视口设置 glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w<=h)//描绘了两种不同情况下的平行修剪空间 glOrtho(-0.6,0.6,-0.6*(GLfloat)h/(GLfloat)w,0.6*(GLfloat)h/(GLfloat)w,-10.0,10.0); else glOrtho(-0.6*(GLfloat)w/(GLfloat)h,0.6*(GLfloat)w/(GLfloat)h,-0.6,0.6,-10.0,10.0); glMatrixMode(GL_MODELVIEW); } #defineGLUT_WHEEL_UP3//定义滚轮操作 #defineGLUT_WHEEL_DOWN4 voidmouse(intbtn,intstate,intx,inty) { if(btn==GLUT_LEFT_BUTTON&&state==GLUT_DOWN){ Laplacian(); } if(btn==GLUT_MIDDLE_BUTTON&&state==GLUT_DOWN)axis=0; if(btn==GLUT_RIGHT_BUTTON&&state==GLUT_DOWN)axis=1; theta[axis]+=2.0; if(theta[axis]>360.0)theta[axis]-=360.0; display(); } voidkeys(unsignedcharkey,intx,inty){ if(key=='a') Tran[0]-=0.2; i
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 图形学 实验 报告