OpenGL画小球(无光照渲染)

来源:互联网 发布:帝国cms自带的采集 编辑:程序博客网 时间:2024/04/29 07:40

#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函数是OpenGLGLUT工具包中用于实现双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区指针。 使用glutSwapBuffers函数需要glutInitDisplayMode函数中时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE)。这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用双缓冲而非单缓冲。 


第二份代码中使用了单缓冲技术。

   glutInitDisplayMode函数中时, 开启GLUT_SINGLE。glFlush函数是强制刷新,强制马上输出命令执行的结果,而不是存储在缓冲区中,继续等待其他OpenGL命令。因为OPENGL是使用一条渲染管线线性处理命令的,一般情况下,我们提交给OPENGL的指令并不是马上送到驱动程序里执行的,而是放到一个缓冲区里面,等这个缓冲区满了再一次过发到驱动程序里执行;很多时候只有几条指令是填充不满那个缓冲区的,这就是说这些指令根本没有被发送到驱动里,所以我们要调用glFlush来强制把这些指令送到驱动里进行处理。

因此使用该技术,可以看到每次画图的过程,而不是直接显示最终结果。