OpenGL课程设计三维球体的实现.docx
- 文档编号:18375575
- 上传时间:2023-08-16
- 格式:DOCX
- 页数:20
- 大小:339.27KB
OpenGL课程设计三维球体的实现.docx
《OpenGL课程设计三维球体的实现.docx》由会员分享,可在线阅读,更多相关《OpenGL课程设计三维球体的实现.docx(20页珍藏版)》请在冰点文库上搜索。
OpenGL课程设计三维球体的实现
游戏软件设计课程报告
(三维球体的实现)
院 系:
专 业:
学 号:
姓 名:
指导教师:
2010年10月10日
一、应用程序的最终界面----------------------------------------------------------------1
二、三维球体的绘制---------------------------------------------------------------------2
1、球体绘制方法研究----------------------------------------------------------------2
2、面分解法的实现----------------------------------------------------------------3
2.1 面分解函数----------------------------------------------------------------3
2.2 初值的选取----------------------------------------------------------------3
2.3球体的实现----------------------------------------------------------------4
3、三角形绘制函数----------------------------------------------------------------4
4、三角面法向量函数----------------------------------------------------------------5
5、点的模长扩展函数----------------------------------------------------------------5
6、南北极法的实现----------------------------------------------------------------5
7、动画的实现-------------------------------------------------------------------10
三、二种绘制方法的比较---------------------------------------------------------------12
一、应用程序的最终界面
本OpenGL应用程序的最终界面主要由二部分构成,其一是参数控制栏,其二是视图显示窗。
如下图如示。
当通过左边的控制面板来修改球体参数时,右边的视图窗口即会显示出用户操作所产生的效果。
二、三维球体的绘制
1、球体绘制方法研究
OpenGL绘制几何图形,本人认为关键的一步在于建立物体的几何模型。
我们通过不同的规则来对同一个物体建模,将会得到很不相同的结果。
把物体的模型建设好,即能用数学表达式来表达或说构建出一个物体,那么用OpenGL将其画出来或说表达出来,将不会是一件很困难的事情。
如何建立球体模型呢?
由于我们实际的生活经验不难发现,地球可以抽象为一个理想的球体,而地球的定位一般是通过经度纬度值。
也就是说只要有二个参数就基本上可以确定一个球体上的点的几何位置。
基于此,首先可用经纬特征来构建一个球体模型。
假想好球体也分为南北二极,再选取一个点为经度的零点,这样便可以把球体想成是由很多的水平圆和竖直圆来包围着的。
而这些圆与圆的交点就构造出了很多的小平面,我们画球的目的就是要将这些小平面一个个画出来。
每个小平面再分为二个三角面,这样使每个经纬相交的点对应着二个小三角面。
4个顶点由经纬度是容易确定的,从而2个小三角面也就易于在OpenGL中勾画出来。
如下图所示:
当然,像球这样规则的几何体还有一个更普通的建模方法,在此简称为面分解法:
即是先想像出构造出该物体的最小单元,由此画出逼近物体最粗糙或说最失真的图形。
再由该最失真图形一步步细化,从而慢慢逼近最真实的图形。
球体可以想像是由很多的小三角面构成,球体最粗糙的图形可以认为是一个正4面体,它的面分解法原理是将每个三角面分再分为更小的三角面,其过程表述如下:
取初始三角形三边上的中点,将该三点模长扩展为球体半径长度,再将原始三点与现在三点结合,构成了4个小三角形。
其图形表示如下:
2、面分解法的实现
2.1 面分解函数
参数v1,v2,v3为初始三角面的三个顶点向量,count记录当前要分解的级数,也就是当前该面要进行等分的次数。
若count=0,则不需要等分,而直接以初始三个顶点画三角面。
若count=1,则要等分一次,若count=2,则要进行二次等分,最终该原始三角面将被分为1*4*4=16个。
依次类推。
程序实现代码如下:
voidCVRworkView:
:
SubDivide(float*v1,float*v2,float*v3,intcount)
{
//count为等分级数
if(0>=count)//count=0,则画由三点构成的三角形
{
DrawTriangle(v1,v2,v3);
}
else
{
GLfloatv12[3],v23[3],v31[3];
GLinti;
for(i=0;i<3;i++){
v12[i]=(v1[i]+v2[i])/2;//求取等分的中点坐标
v23[i]=(v2[i]+v3[i])/2;
v31[i]=(v3[i]+v1[i])/2;
}
Normalize(v12,(float)m_nRadius);//将所得中点进行模长扩展
Normalize(v23,(float)m_nRadius);
Normalize(v31,(float)m_nRadius);
SubDivide(v1,v12,v31,count-1);//对所产生的4个新的三角面再进行等分
SubDivide(v2,v23,v12,count-1);
SubDivide(v3,v31,v23,count-1);
SubDivide(v12,v23,v31,count-1);
}
}
2.2 初值的选取
2.1介绍的是针对一个普通面的分解办法,进行其操作的前提是要已知经初始的三个顶点。
实际中初始面(初始图形)的设计是有一定艺术水平的。
初始图形构造的好,不仅图形的空间位置易于确定,而且也容易构造出更逼真的图形。
在一般的参考书上,球体的初始图形是一个正20面体,当然,这是一个很好的办法。
但在本次设计中,球体的初始图形设置为由6个点构成的8面体,之所以这样做,是因为这样更有利于理解球体图形的生成,而且这样也方便确定各点的空间坐标。
所构成的图形如下图所示述:
初始的六个点都取自于坐标轴,关于原点对称地在各坐标轴上取二点,从而易写出一个适合坐球体初始图形的各点的坐标如下:
P1(r,0,0),P2(-r,0,0)
P3(0,0,r),P4(0,0,-r)
P5(0,r,0),P6(0,-r,0)
2.3球体的实现
voidCVRworkView:
:
DrawGeometry()
{
GLfloatr=(GLfloat)m_nRadius;
GLfloatvdata[6][3]={//初始点坐标
{r,0.0,0.0},{-r,0.0,0.0},
{0.0,r,0.0},{0.0,-r,0.0},
{0.0,0.0,r},{0.0,0.0,-r}
};
GLuinttindices[8][3]={//初始面的构造
{2,4,0},{2,0,5},{2,5,1},{2,1,4},
{3,0,4},{3,5,0},{3,1,5},{3,4,1}
};
for(inti=0;i<8;i++){//绘制球体
SubDivide(&vdata[tindices[i][0]][0],
&vdata[tindices[i][1]][0],
&vdata[tindices[i][2]][0],m_nCount);
}
}
3、三角形绘制函数
voidCVRworkView:
:
DrawTriangle(float*v1,float*v2,float*v3)
{
//以三点为顶点画三角形
GLfloatnormal[3]={0,0,0};
NormalTriangle(v1,v2,v3,normal);//求取面法向量
glBegin(m_nPattern);
glNormal3fv(normal);
glVertex3fv(v1);
glVertex3fv(v2);
glVertex3fv(v3);
glEnd();
}
4、三角面法向量函数
经验认为,画图时面法向量的方向判定是很关键的。
有时,所画出的图形经常看到黑白相间,使不当显示的地方却能够被人眼所看到,那么这类问题一般都是因为法向量的方向计算有误。
voidCVRworkView:
:
NormalTriangle(float*v1,float*v2,float*v3,float*vout)
{
//求三点构成的三角形面的法向量
GLfloatv12[3],v23[3];
for(inti=0;i<3;i++){
v12[i]=v2[i]-v1[i];
v23[i]=v3[i]-v2[i];
}
vout[0]=v12[1]*v23[2]-v12[2]*v23[1];
vout[1]=-(v12[0]*v23[2]-v12[2]*v23[0]);
vout[2]=v12[0]*v23[1]-v12[1]*v23[0];
Normalize(vout,1);
}
5、点的模长扩展函数
当细分三角面的时候,求取中点之后还需要将该中点的模长扩展为球半径的长度,这样才会使新增的点属于球体面上的点,从而画的图形才不会失真,不会有突高突低的形状。
扩展模长的方法很简单,即是使点的失量方向不改变,只增大其模长。
代码如下述:
voidCVRworkView:
:
Normalize(float*v,floatradius)
{
//向量的标准化,以模长为radius进行标准化
GLfloatd=(GLfloat)sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
if(d==0.0){
return;
}
v[0]/=d;v[1]/=d;v[2]/=d;
v[0]*=radius;v[1]*=radius;v[2]*=radius;
}
6、经纬度法的实现
按一定的角度分解出单位纬度,然后再按一定的角度分解出单位经度,由此可得画小三角面的循环次数以及各点上的经纬值,从而可画出图形。
代码如下述:
voidCTestView:
:
DrawSphere()
{
constfloatPI=(float)3.1415926;
constfloatradius=10.0;//定义球半径值
constGLfloatfLongUnit=5;//定义经度单位角度数
constGLfloatfLatUnit=5;//定义纬度单位角度数
GLfloatfLongitude=0;//当前点位置的经度数
GLfloatfLatitude=0;//当前点位置的纬度数
GLfloatfLongitudeNext=0;//当前点位置的下一位置经度值
GLfloatfLatitudeNext=0;//当前点位置的下一位置纬度值
GLfloatalpha=0;//当前点位置的经度弧度值
GLfloatbeta=0;//对应的纬度弧度值
GLfloatalphaNext=0;//下一位置的经度弧度值
GLfloatbetaNext=0;//下一位置的纬度弧度值
GLfloatvPointA[3]={0,0,0};//当前位置的点位置向量
GLfloatvPointA1[3]={0,0,0};//三个相邻位置的点位置向量
GLfloatvPointA2[3]={0,0,0};
GLfloatvPointA3[3]={0,0,0};
GLfloatvFace[3]={0,0,0};//定义面的法向量,每个顶点对应二个面
GLfloatvFaceNext[3]={0,0,0};
inti=0,j=0,nCountLong=0,nCountLat=0;//循环变量
nCountLat=(int)(180/fLatUnit);
nCountLong=(int)(360/fLongUnit);//求得循环次数
//先画南北极的三角扇形即i=0,i=nCountLat
fLatitude=fLatUnit;//北极扇形
beta=(PI/180)*fLatitude;
vPointA[0]=0;
vPointA[1]=0;
vPointA[2]=radius;
for(j=0;j { fLongitude=j*fLongUnit; fLongitudeNext=fLongitude+fLongUnit; alpha=(PI/180)*fLongitude; alphaNext=(PI/180)*fLongitudeNext; vPointA1[0]=radius*sin(beta)*cos(alpha); vPointA1[1]=radius*sin(beta)*sin(alpha); vPointA1[2]=radius*cos(beta); vPointA2[0]=radius*sin(beta)*cos(alphaNext); vPointA2[1]=radius*sin(beta)*sin(alphaNext); vPointA2[2]=radius*cos(beta); GLfloatvAA1[3]={0,0,0};//定义各临时向量,以备注三角面的法向量 GLfloatvA1A2[3]={0,0,0}; intk=0; for(k=0;k<3;k++){ vAA1[k]=vPointA1[k]-vPointA[k]; vA1A2[k]=vPointA2[k]-vPointA1[k]; } for(k=0;k<3;k++){ vFace[k]=vAA1[k]*vA1A2[k]; } glBegin(GL_TRIANGLES); glNormal3fv(vFace); glColor3ub(0xff,0xff,0xff); glVertex3fv(vPointA); glColor3ub(0,255,0); glVertex3fv(vPointA1); glColor3ub(0,0,255); glVertex3fv(vPointA2); glEnd(); } fLatitude=180-fLatUnit;//南极扇形 beta=(PI/180)*fLatitude; vPointA[0]=0; vPointA[1]=0; vPointA[2]=-radius; for(j=0;j { fLongitude=j*fLongUnit; fLongitudeNext=fLongitude+fLongUnit; alpha=(PI/180)*fLongitude; alphaNext=(PI/180)*fLongitudeNext; vPointA1[0]=radius*sin(beta)*cos(alpha); vPointA1[1]=radius*sin(beta)*sin(alpha); vPointA1[2]=radius*cos(beta); vPointA2[0]=radius*sin(beta)*cos(alphaNext); vPointA2[1]=radius*sin(beta)*sin(alphaNext); vPointA2[2]=radius*cos(beta); GLfloatvAA1[3]={0,0,0};//定义各临时向量 GLfloatvA1A2[3]={0,0,0}; intk=0; for(k=0;k<3;k++){ vAA1[k]=vPointA1[k]-vPointA[k]; vA1A2[k]=vPointA2[k]-vPointA1[k]; } for(k=0;k<3;k++){ vFace[k]=vAA1[k]*vA1A2[k]; } glBegin(GL_TRIANGLES); glNormal3fv(vFace); glColor3ub(0xff,0xff,0xff); glVertex3fv(vPointA); glColor3ub(0,255,0); glVertex3fv(vPointA1); glColor3ub(0,0,255); glVertex3fv(vPointA2); glEnd(); } //以下画中间的点 for(i=1;i {//顶点需要单独处理 fLatitude=i*fLatUnit;//计算当前点的纬度数 fLatitudeNext=fLatitude+fLatUnit;//计算它的下一纬度 beta=(PI/180)*fLatitude;//计算对应的弧度值 betaNext=(PI/180)*fLatitudeNext; for(j=0;j { fLongitude=j*fLongUnit;//计算经度 fLongitudeNext=fLongitude+fLongUnit; alpha=(PI/180)*fLongitude; alphaNext=(PI/180)*fLongitudeNext; //以下求得各点的坐标值,以计算方向向量之用 vPointA[0]=radius*sin(beta)*cos(alpha); vPointA[1]=radius*sin(beta)*sin(alpha); vPointA[2]=radius*cos(beta); vPointA1[0]=radius*sin(beta)*cos(alphaNext); vPointA1[1]=radius*sin(beta)*sin(alphaNext); vPointA1[2]=radius*cos(beta); vPointA2[0]=radius*sin(betaNext)*cos(alpha); vPointA2[1]=radius*sin(betaNext)*sin(alpha); vPointA2[2]=radius*cos(betaNext); vPointA3[0]=radius*sin(betaNext)*cos(alphaNext); vPointA3[1]=radius*sin(betaNext)*sin(alphaNext); vPointA3[2]=radius*cos(betaNext); //以下求取各面的法向量 GLfloatvAA1[3]={0,0,0};//定义各临时向量 GLfloatvA1A3[3]={0,0,0}; GLfloatvAA2[3]={0,0,0}; GLfloatvA2A3[3]={0,0,0}; intk=0; for(k=0;k<3;k++){ vAA1[k]=vPointA1[k]-vPointA[k]; vA1A3[k]=vPointA3[k]-vPointA1[k]; vAA2[k]=vPointA2[k]-vPointA[k]; vA2A3[k]=vPointA3[k]-vPointA2[k]; } for(k=0;k<3;k++){ vFace[k]=vAA1[k]*vA1A3[k]; vFaceNext[k]=vAA2[k]*vA2A3[k]; } //画点对应的二个小三角形 glBegin(GL_TRIANGLES); glNormal3fv(vFace); glColor3ub(0xff,0,0); glVertex3fv(vPointA); glColor3ub(0,255,0); glVertex3fv(vPointA1); glColor3ub(0,0,255); glVertex3fv(vPointA3); glEnd(); glBegin(GL_TRIANGLES); glNormal3fv(vFace); glColor3ub(0xff,0,0); glVertex3fv(vPointA); glColor3ub(0x00,0xff,0x00); glVertex3f
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- OpenGL 课程设计 三维 球体 实现