博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

OpenGL

Posted on 2012-06-08 11:05  xgbzsc  阅读(572)  评论(0编辑  收藏  举报
OpenGL是
  • OpenGL是一个操纵硬件的软件接口
  • 包含大约250个函数(GLU中50个)
  • 没有执行窗口任务的函数
  • 没有获取用户输入的函数
  • 没有描述高级三维模型例如汽车/人等的高级函数
  • 只有描述几何图元的函数(点/直线/多边形)
  • OpenGL实用库(GLU)提供了高级特性(二次曲面,NURBS曲线,曲线)
 
渲染,指计算机根据模型创建图像。
模型,是有几何图元(点/直线/多边形)构成的。
几何图元,由顶点指定。vertex
最终渲染的图像,由屏幕像素组成。
像素是显示硬件能够放置到屏幕上的最小的可视元素。
有关像素的信息,如颜色,在系统内存中被组织为位面bitplane。
bitplane是一块内存区域,存储屏幕上一个像素所需的信息。
许多位面一起,构成了帧缓冲
 
OpenGL函数命名规则
gl + 函数功能描述 + 数字,表示接收参数个数 + f/d等字母,表示接收参数类型,其中v表示指针/数组。
 
OpenGL是一个状态机

当设置了状态之后,直到下一次修改设置之前,状态都有效。

glEnable()和glDisable()启用和禁用某状态。

glGetBooleanv();glGetDoublev();glGetFloatv();glGetIntegerv();glGetPointerv();glIsEnable(),六个函数都返回状态值,只是类型不同。也可以使用更具体的glGetLight*()等。

另外可以使用glPushAttrib()和alPopAttrib()将一组状态变量的值保存到属性堆栈中,暂时修改它们。将来使用glPopAttrib()和glPopClientAttrib()恢复。就暂时修改状态而言,使用该方法可能比使用查询函数效率更高。OpenGL渲染流水线

 
 
 
 
 
OpenGL渲染流水线

 

OpenGL函数库

相关链接:http://www.cnblogs.com/mumuliang/archive/2010/07/13/1873512.html 

实用库GLU:包含多个低级OpenGL函数(设置视点矩阵、投影矩阵、执行多边形网格化、渲染曲面等的函数)所有OpenGL都实现了这个函数库。

用于扩展窗口系统以支持OpenGL的函数库 :X窗口的扩展GLX;MS的扩展WGL,IBM OS/2的PGL,Mcintosh的AGL。

OpenGL实用工具包GLUT:是一个独立于窗口系统的工具包。

OpenGL扩展GLEX: 硬件厂商新增的特性可能没有在gl.h中,为了让程序员使用新的OpenGL扩展,就有了glext.h。

 

包含文件 

#include <GL/gl.h>
#include 
<GL/glu.h>

包含了硬件厂商新特性的glex

#include <GL/glext.h> 

如果使用了窗口接口

复制代码
#include <GL/WGL.h>   //windows,函数以wgl开头   
#include <windows.h>

#include <GL/AGL.h>//Apple Macintosh,函数以agl开头

#include <...>

#include <GL/PGL.h>//IBM OS/2,函数以pgl开头

#include <...> 

#include <GL/glx.h>//X系统,函数以glX开头,前面三个都是先*后gl,这个是先gl后X

#include <X11/Xlib.h>  

复制代码

其他可能用到的

#include <stdlib.h>
#include 
<stdio.h>

 

OpenGL实用工具包(GLUT)

OpenGL是针对硬件的一个软件接口,独立于操作系统,因此它本身并没有被(要求)设计出打开窗口、响应键盘这一类的函数。但unfortunatly,要运行一个程序,总是需要窗口的,而操作图形总是要响应某种设备。GLUT库也就是为此而生的。

GL核心库中的绘图函数只能画点/线和多边形。因此GLUT在提供窗口操作事件响应以外顺便提供了一些绘制复杂三维图形的函数,例如球体/圆环/茶壶(OpenGL内置了茶壶,很有意思)。除此以外,GLUT提供了二次函数,用于创建三维物体。

 

1.窗口管理

    1)glutInit(int * argc, char ** argv)

         初始化GLUT并处理命令行参数。 应用在其他GLUT函数之前

    2)glutInitDisplayMode(unsigned int mode)

        指定颜色模式:是RGBA还是索引模式 ;是双缓冲还是单缓冲;窗口是否有关联的深度缓存/模板缓存/累计缓存。

        如果使用索引模式,需要将一些颜色加载到颜色表,使用glutSetCorlor()。 

        希望窗口使用双缓存和RGBA颜色模式并有深度缓存,just do this:

        glulInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH)

    3)glutInitWindowPostion(int x,int y)

        指定窗口左上角位置

    4)glutInitWindowSize(int width, int size)

        指定窗口大小

    5)int glutCreateWindow(char *string)

        使用一个OpenGL场景创建一个窗口,该函数返回该窗口的惟一标识符。

        * 在glutMainLoop()之前,窗口不会被显示出来。

 

2.显示回调函数

    1)glutDisplayFunc(void (*func)(void))

        最最最最重要的事件回调,每当GLUT认为需要重新显示窗口内容时,都将执行glutDisplayFunc注册的回调函数。也就是重新绘制场景所需要调用的函数都被它注册过。

        如果程序修改了窗口内容,可能需要调用函数glutPostRedisplay(void),它提醒函数glutMainLoop()调用注册的显示回调函数。

 

3. 运行程序

    1)glutMainLoop(void)

        直到调用glutMainLoop(void)之后, 

        ·创建的所有窗口才被显示

        ·被渲染到窗口中的内容才被显示

        ·程序开始事件处理

        ·注册的回调函数被触发

        ·该循环一旦开始便不会退出 

 

 4. 处理输入事件

    1)glutReshapeFunc(void(*func)(int w, int h)) 

        当窗口大小发生改变时,应采取的措施

    2)glutKeyboardFunc(void(*func)(unsigned char key, int x, int y) )

         glutMouseFunc(void(* func)(int button, int state, int x, int y ) )

        指定当特定的键或鼠标按钮被按下或松开时应调用的函数

    3)glutMotionFunc(void(* func)(int x, int y))

        指定当用户按下鼠标并移动鼠标时应调用的回调函数  

 

5. 管理后台处理

    1)glutIdleFunc(void (*func)(void))

         指定一个在没有其他事件需要处理时,如事件循环空闲时执行的函数。该函数唯一的参数是一个函数指针,使用参数NULL或0调用该函数,可注销空闲时执行的函数。

 

6. 绘制三位物体

    GLUT提供了绘制下列9种三维物体的函数: 

    四面体;八面体;十二面体;二十面体;立方体;球体;圆锥体;圆环;茶壶。

    可以以 线框 或 实体 两种形式绘制。实体绘制时,需要制定面法线。例如绘制球体和立方体的函数:

    1)void glutWireCube(GLdouble size);

    2)void glutSolideCube(GLdouble size);

    3)void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);

    4)glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);

 

 

动画,双缓冲

电影24帧/秒。计算机动画制作一部包括1,000,000帧的电影,可能如下

复制代码
open_window();
for(int i=0; i<1000000; i++)
{
    clear_the_window();
    draw_frame(i);
    wait_until_a_24th_of_ascend_is_over();
}
复制代码

由于clear和draw都要耗费时间因此,在1/24秒内,看到的是一个绘制过程,如果绘制时间太长,甚至来不及绘制完成就被clear掉开始了下一帧的draw。双缓冲的意义就是,先绘制好,到了1/24秒,直接拿给观众看。 

复制代码
open_window_in_double_buffer_mode(); 
for(i =0; i<1000000; i++) 
{
    clear_the_window();
    draw_frame(i);
    swap_the_buffers();

}

复制代码

在有些OpenGL实现中,除了交换被显示和被绘制的缓存外,swap_the_buffers还等待当前屏幕更新结束,以保证前一个缓存被完整显示。 

* 通常对于每一帧,重新绘制整个缓存比判断哪一部分需要重新绘制更容易。

OpenGL核心库没有提供swap_the_buffers函数,因为并非所有硬件都支持。GLUT库中有glutSwapBuffers(void)。

 

使用双缓存的一个例子
复制代码
#include <Windows.h>

#include 
<gl/glut.h>

// 旋转角度
static GLfloat spin = 0.0;

void init(void)
{
    glClearColor(
0.0,0.0,0.0,0.0);
    glShadeModel(GL_FLAT);
}

void  createRect(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    
// 这里使用glPushMatrix和glPopMatrix对
    
// 上例使用glBegin和glEnd对
    glPushMatrix();
    glRotatef(spin, 
0.0,0.0,1.0);
    glColor3f(
1.0,1.0,1.0);
    glRectf(
-25.0,-25.0,25.0,25.0);
    glPopMatrix();
    
    
// 交换缓存
    glutSwapBuffers();
}

void spinRect(void)
{
    spin 
= spin +2.0;
    
if (spin>360.0)
    {
        spin 
= spin-360.0;
    }
    
// 显示?
    glutPostRedisplay();
}

void reshape(int w, int h)
{
    glViewport(
0,0, (GLsizei)w,(GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(
-50.0,50.0,-50.0,50.0,-1.0,1.0);
    glMatrixMode(GL_MODELVIEW);
    
// ???
    glLoadIdentity();
}

void mouse(int button, int state, int x, int y)
{
    
switch (button)
    {
    
case GLUT_LEFT_BUTTON:
        
if (state == GLUT_DOWN)
            
// 在空闲时spinRect
            glutIdleFunc(spinRect);
        
break;
    
case GLUT_MIDDLE_BUTTON:
        
if (state == GLUT_DOWN)
            
// 停止空闲时的操作
            glutIdleFunc(NULL);
        
break;
    
default:
        
break;
    }
}

int main(int argc, char** argv)
{
    
// GLUT初始化窗口的5个必须的步骤
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE
|GLUT_RGBA);
    glutInitWindowPosition(
250,250);
    glutInitWindowSize(
400,400);
    glutCreateWindow(
"Hello");

    
// 一些初始化操作
    init();

    
// 添加回调*****重要
    glutDisplayFunc(createRect);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);

    
// 真正开始绘制
    glutMainLoop();

    
return 0;
}
复制代码