#define GLUT_DISABLE_ATEXIT_HACK
#include <gl/glut.h>
#include <gl/glu.h>
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f( 1.0f, 1.0f, 1.0f );
glutSolidSphere( 50.f, 15, 15 ); //glutSolidSphere中的第一个参数太大,要小于1才能看到,第一个参数为半径
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow("小球");
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
上述的代码会画出实心球,整个实心小球是一个颜色,立体效果差,若想显示立体效果,需要用颜色,光照等渲染。
下面的代码画出球比较慢,是按照一个一个切面的圆显示出来的,最终为这些切面组成的网状图。这个球的立体感较强,但是画一个球的时间较长。
//球心坐标为(x,y,z),球的半径为radius,M,N分别表示球体的横纵向被分成多少份
void drawSphere(GLfloat xx, GLfloat yy, GLfloat zz, GLfloat radius, GLfloat M, GLfloat N)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f( 1.0f, 1.0f, 1.0f );
float step_z = PI/M;
float step_xy = 2*PI/N;
float x[4],y[4],z[4];
float angle_z = 0.0;
float angle_xy = 0.0;
int i=0, j=0;
glBegin(GL_POLIGON);
for(i=0; i<M; i++)
{
angle_z = i * step_z;
for(j=0; j<N; j++)
{
angle_xy = j * step_xy;
x[0] = radius * sin(angle_z) * cos(angle_xy);
y[0] = radius * sin(angle_z) * sin(angle_xy);
z[0] = radius * cos(angle_z);
x[1] = radius * sin(angle_z + step_z) * cos(angle_xy);
y[1] = radius * sin(angle_z + step_z) * sin(angle_xy);
z[1] = radius * cos(angle_z + step_z);
x[2] = radius*sin(angle_z + step_z)*cos(angle_xy + step_xy);
y[2] = radius*sin(angle_z + step_z)*sin(angle_xy + step_xy);
z[2] = radius*cos(angle_z + step_z);
x[3] = radius * sin(angle_z) * cos(angle_xy + step_xy);
y[3] = radius * sin(angle_z) * sin(angle_xy + step_xy);
z[3] = radius * cos(angle_z);
for(int k=0; k<4; k++)
{
glVertex3f(xx+x[k], yy+y[k],zz+z[k]);
}
}
}
glEnd();
}
注意glvertex3f函数,各个坐标均在0~1之间,如果参数不满足上述要求,则不能画出球形。屏幕为背景色。
glbegin的模式参数决定图像的立体感,如果为GL_QUADS,立体感较差。如果未GL_POLYGON,立体感稍好一些。
这里需要说明一点,第一份代码中使用了双缓冲技术。
通常, 我们所看到的窗体、文字、图像,从根本上来说都是“画”出来的。比如,制作一个简单的五子棋, 我们可能先要绘制棋盘,然后绘制棋子,我们可能还要绘制一些提示信息。虽然这些绘制操作有一定的先后顺序,通常情况下,操作系统的这些绘制速度非常的快,使人眼误认为这些绘制操作是同时完成的。
但当我们进行复杂的绘图操作时,画面便可能有明显的闪烁。解决这个问题的关键在于使绘制的东西同时出现在屏幕上。所谓双缓冲技术, 是指使用两个缓冲区: 前台缓冲和后台缓冲。前台缓冲即我们看到的屏幕,后台缓冲则在内存当中,对我们来说是不可见的。每次的所有绘图操作都在后台缓冲中进行, 当绘制完成时, 把绘制的最终结果复制到屏幕上, 这样, 我们看到所有GDI元素同时出现在屏幕上,从而解决了频繁刷新导致的画面闪烁问题。
glutSwapBuffers函数是OpenGL中GLUT工具包中用于实现双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区指针。 使用glutSwapBuffers函数需要在glutInitDisplayMode函数中时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE)。这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用双缓冲而非单缓冲。
第二份代码中使用了单缓冲技术。
在glutInitDisplayMode函数中时, 开启GLUT_SINGLE。glFlush函数是强制刷新,强制马上输出命令执行的结果,而不是存储在缓冲区中,继续等待其他OpenGL命令。因为OPENGL是使用一条渲染管线线性处理命令的,一般情况下,我们提交给OPENGL的指令并不是马上送到驱动程序里执行的,而是放到一个缓冲区里面,等这个缓冲区满了再一次过发到驱动程序里执行;很多时候只有几条指令是填充不满那个缓冲区的,这就是说这些指令根本没有被发送到驱动里,所以我们要调用glFlush来强制把这些指令送到驱动里进行处理。
因此使用该技术,可以看到每次画图的过程,而不是直接显示最终结果。