OpenGL绘制几何图形,本人认为关键的一步在于建立物体的几何模型。我们通过不同的规则来对同一个物体建模,将会得到很不相同的结果。把物体的模型建设好,即能用数学表达式来表达或说构建出一个物体,那么用OpenGL将其画出来或说表达出来,将不会是一件很困难的事情。如何建立球体模型呢?
由于我们实际的生活经验不难发现,地球可以抽象为一个理想的球体,而地球的定位一般是通过经度纬度值。也就是说只要有二个参数就基本上可以确定一个球体上的点的几何位置。基于此,首先可用经纬特征来构建一个球体模型。假想好球体也分为南北二极,再选取一个点为经度的零点,这样便可以把球体想成是由很多的水平圆和竖直圆来包围着的。而这些圆与圆的交点就构造出了很多的小平面,我们画球的目的就是要将这些小平面一个个画出来。每个小平面再分为二个三角面,这样使每个经纬相交的点对应着二个小三角面。4个顶点由经纬度是容易确定的,从而2个小三角面也就易于在OpenGL中勾画出来。
参数v1,v2,v3为初始三角面的三个顶点向量,count记录当前要分解的级数,也就是当前该面要进行等分的次数。若count = 0,则不需要等分,而直接以初始三个顶点画三角面。若count = 1,则要等分一次,若count = 2,则要进行二次等分,最终该原始三角面将被分为1*4*4 = 16个。依次类推。程序实现代码如下:
void CVRworkView::SubDivide(float *v1, float *v2, float *v3, int count)
{
//count为等分级数
if(0 >= count) //count=0,则画由三点构成的三角形
{
DrawTriangle(v1,v2,v3);
}
else
{
GLfloat v12[3],v23[3],v31[3];
GLint i;
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);
}
}
前面讲述的是大众的面分解法,实际中初始面(初始图形)的设计是有一定艺术水平的。初始图形构造的好,不仅图形的空间位置易于确定,而且也容易构造出更逼真的图形。在一般的参考书上,球体的初始图形是一个正20面体,当然,这是一个很好的办法。但在本次设计中,球体的初始图形设置为由6个点构成的8面体,之所以这样做,是因为这样更有利于理解球体图形的生成,而且这样也方便确定各点的空间坐标。所构成的图形如下图所示述:
这样就可以如下来绘制球体:
void CVRworkView::DrawGeometry()
{
GLfloat r = (GLfloat)m_nRadius;
GLfloat vdata[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}
};
GLuint tindices[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(int i = 0; i < 8; i++){ //绘制球体
SubDivide(&vdata[tindices[i][0]][0],
&vdata[tindices[i][1]][0],
&vdata[tindices[i][2]][0],m_nCount);
}
}
每个面又是由2个三角形组成,如下绘制每个三角形:
void CVRworkView::DrawTriangle(float *v1, float *v2, float *v3)
{
//以三点为顶点画三角形
GLfloat normal[3] = {0,0,0};
NormalTriangle(v1,v2,v3,normal); //求取面法向量
glBegin(m_nPattern);
glNormal3fv(normal);
glVertex3fv(v1);
glVertex3fv(v2);
glVertex3fv(v3);
glEnd();
}
最终形成的球面如下: