OpenGL 前凑

  OpenGL图形系统是一个软件接口,让程序员能够创建交互式程序。
  


  OpenGL编程指南第一章

  概念:1.渲染,指的是计算机根据模型创建图像。模型,是由几何图元(点、直线、多边形)构成的,而几何图元是通过顶点来指定的。
     2.最终渲染的图像由屏幕像素组成:像素(pixel)是显示器硬件能够放置到屏幕上的最小可视元素。有关像素的信息(如颜色)在系统内存中被组织为位面。位面(bitplane)是一块内存区域,为屏幕上的每一个像素存储一位信息,例如像素的红色分量值。位面构成了帧缓存,后者包含图形显示设备为控制屏幕上所有像素的颜色和亮度所需的信息。

  第一个OpenGL实例:

 1     glClearColor(0.0, 0.0, 0.0, 0.0);
2 glClear(GL_COLOR_BUFFER_BIT);
3 glColor3f(1.0, 1.0, 1.0);
4 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
5 glBegin(GL_POLYGON);
6 glVertex3f(0.25, 0.25, 0.0);
7 glVertex3f(0.75, 0.25, 0.0);
8 glVertex3f(0.75, 0.75, 0.0);
9 glVertex3f(0.25, 0.75, 0.0);
10 glEnd();
11 glFlush();
12 }

  函数glClearColor()设置清除颜色,gClear()执行清楚操作。设置清除颜色后,只要调用函数glClear()执行清除操作。设置清除颜色后,只要调用函数glClear()就会用指定的颜色来清除窗口。要修改清除颜色,可再此调用函数glClearColor()。同样,函数glClearColor3f()设置绘制物体时使用的颜色(这里为白色)。之后所有的物体都将使用这种颜色来绘制,直到再次调用函数glClearColor3f()重新设置绘图颜色为止。
  下一个OpenGL函数glOrtho()指定坐标系,OpenGL将根据该坐标系来绘制最终的图像,并决定如何将图像映射到屏幕上。位于函数glBegin()和glEnd()之间的函数调用指定了要绘制的物体(这里为一个包含4个顶点的多边形)。多边形的顶点是由函数glVertex3f()指定的。根据参数((x,y,z)坐标)可知,该多边形是一个位于平面z=0上的矩形。最后,函数glFush()确保绘图函数得以执行,而不是存储在缓存中,等到有更多的OpenGL函数后再执行。

  OpenGL函数的语法
  
在应用程序中始终使用OpenGL定义的数据类型,可确保在两种OpenGL实现之间移植应用程序时,不会出现数据类型不匹配的问题。

  有些OpenGL函数的名称中包含后缀“v”,这表明它将一个指向向量(数组)的指针(而不是一系列的值)作为参数。很多函数都有向量版本和非向量版本,但有些函数只接受数值参数,而其他一些函数则至少要求有些参数为向量。
  GLvoid,这种数据类型最常用于将数组指针作为参数的OpenGL函数中。

  OpenGL是一个状态机  
  
它是一个状态机。它将你指定的各种状态中,知道你修改这些状态为止。当前颜色是一个状态变量。可以将当前颜色设置为白色、红色或其他任意一种颜色,接下来所有物体都将用这种颜色绘制,知道当前颜色被设置为其他颜色。当前颜色只是OpenGL存储的众多状态变量之一;其他一些状态变量控制诸如当前视点变换和投影变换、直线和多边形的点画模式、多边形绘制模式、像素封装方式、光源的位置和特征、物体的材料属性等内容。很多状态变量称为模式,可以使用函数glEnalbe() glDisable()来启用和禁用它们。每个状态变量(模式)都有默认值,可以在任何时候向系统查询每个变量的当前值。通常,程序员使用下列6个函数查询:glGetBooleanv()、glGetDoublev()、glGetFloatv()、glGetIntegerv() 、glGetPointerv()、glIsEnabled。具体使用哪个函数取决于你希望以何种数据类型返回查询结果。对于默写状态变量,可以使用更具体的查询函数,如glGetLight*()、glGetError()和glGetPolygonStipple()。另外,可以使用函数glPushAttrib()和glPopAttrib()将一组状态变量的值保存到属性堆栈中,暂时修改它们,然后再使用函数glPopAttrib()和glPopClientAttrib()恢复这些值。就暂时修改状态而言,应使用这些函数而不是查询函数,因为它们的效率可能更高。

  OpenGL渲染流水线(电子书少了一页。。。还好amzon.cn可以在线试读)
  1.显示列表:任何数据,不论它表述的是几何图元还是像素,都可以保存在显示列表(display list)中,供当前或以后使用。当然,也可以不把数据保存在显示列表中,而是立即对数据进行处理,这种模式也叫做立即模式。当一个显示列表执行时,保存的数据就从显示列表中取出,就像在立即模式下直接由应用程序发送的那样。
  2.求值器:所有的几何图元最终都要通过顶点来描述。参数化曲线和表面最初可能是通过控制点(这个点指什么?)以及叫做基函数的多项式函数进行表述的。求值器提供了一种方法,根据控制点计算表示表面的顶点。这种方法是一种多项式映射,它可以根据控制点产生表面法线、纹理坐标、颜色以及空间坐标值。
  3.基于顶点的操作:对于顶点数据,接下来的一个步骤是“基于顶点的操作”,就是把顶点变换为图元。有些类型的顶点数据(例如空间坐标)是通过一个4*4的浮点矩阵进行变换的。空间坐标从3D世界的一个位置投影到屏幕上的一个位置。如果启动了高级特性,这个阶段将更为忙碌。如果使用了纹理,这个阶段还将生成并变换纹理坐标。如果启动了光照,就需要综合变换后的顶点、表面法线、光源位置、材料属性以及其他光照信息进行光照计算,产生最终的颜色值。
  4.像素操作:在OpenGL的渲染管线中,和单路径的几何数据相比,像素数据所经历的流程有所不同。首先,来自系统内存的一个数组中的像素进行解包,从某种格式(像素的原始格式可能有多种)解包为适当数量的数据成分。接着,这些数据被缩放、偏移,并根据一幅像素图进行处理。处理结果先进行截取,然后或者写入到纹理内存,或者发送到光栅化阶段。如果像素数据是从帧缓冲区读取的,就对它们执行像素转换操作(缩放、偏移、映射和截取)。然后,这些结果被包装为一种适当的格式,并返回到系统内存的一个数组中。OpenGL有几种特殊的像素复制操作,可以把数据从帧缓冲区复制到帧缓冲区的其他位置或纹理内存中。这样,在数据写入到纹理内存或者写回到帧缓冲区之前,只需要进行一道像素转换就可以了。
  5.纹理装配:OpenGL应用程序可以在几何物体上应用纹理图像,使它们看上去更为逼真。如果需要使用多幅纹理图像,把它们放在纹理对象中是一种明智的做法。这样,就可以很方便地在它们之间进行切换。几乎所有的OpenGL实现都拥有一些特殊的资源,可以加速纹理的处理(这些资源可能是图形实现中从一个共享资源池中分配而来的)。为了帮助OpenGL实现高效地管理这些内存资源,优先使用纹理对象来帮助控制纹理贴图潜在的缓存和定位问题。
  6.光栅化:就是把几何数据和像素数据转换为片段的过程。每个片段方块对应于帧缓冲区的一个像素。把顶点链接起来形成直线或者计算填充多边形的内部像素时,需要考虑直线和多边形的点画模式、直线的宽度、点的大小、着色模型以及支持抗锯齿处理的覆盖计算。每个片段方块都将具有各自颜色和深度值。
  7.片段操作:在数据实际存储到帧缓冲区之前,要执行一系列操作。这些操作可能会修改甚至丢弃这些片段。所有这些操作都可以启用或禁用。第一个可能执行的操作是纹理处理。在纹理内存中为每个片段生成一个纹理单元(texel,也就是纹理元素),并应用到这个片段上。接下来,组合主颜色和辅助颜色,可能还会应用一次雾计算。如果应用程序使用了片段着色器,前面三个操作可能都在着色其中完成。

  与OpenGL相关的函数库
  1.包含文件:各头文件中包含头文件gl.h。几乎所有的OpenGL应用程序都使用GLU,为此需要包含glu.h。glut.h确保了gl.h和glu.h被正确地包含进来,因此同时包含这3个头文件是多余的。
  2.OpenGL使用工具包:OpenGL包含渲染函数,但被设计成独立于任何窗口系统和操作系统。需要GLUT(发现vs上没有那个库,得自己安装了!先暂时不弄 待续)

  动画
  在图形计算机上,可以完成的最有趣的工作之一是绘制运动画面。

1 open_window();
2 for(i = 0; i < 1 000 000; i++) {
3 clear_the_window();
4 draw_frame(i);
5 wait_until_a_24th_of_a_second_is_over();
6 }

假如绘图需要时间约为1/24妙,那么最先绘制的物体在这1/24妙内是可见的,并在屏幕上出现一幅纯色图像;最后绘制的物体立刻被清除掉,因为程序马上开始下一帧,你看到的是绘制过程。
  大多数OpenGL实现都提供了双缓存技术:支持两个完整颜色缓存的硬件或软件。绘制一个缓存时,显示另一个缓存中的内容。每绘制好一帧,便交换缓存;这样刚才被显示的缓存现在被用来绘制,而用来绘制的缓存被显示。使用双缓存,每一帧都在绘制好后才显示,观众不会看到绘制过程。

View Code
1 open_window_in_double_buffer_mode();
2 for(int i = 0;i < 1000 000;i++) {
3 clear_the_window();
4 draw_frame(i);
5 swap_the_buffers();
6 }

  暂停刷新
  在有些OpenGL实现中,除了交换被显示和被绘制的缓存外,函数swap_the_buffers()还等待当前屏幕更新周期结束,以保证前一个缓存被完整地显示。它使得新缓存得以从头开始完整地显示。假设系统刷新屏幕为每秒60次,这意味着帧频最高可达60fps,如果清除并绘制一帧的时间不超过1/60妙,动画能够以这种速度连贯地播放。
  画面过于复杂,1/60妙内无法画出,这样每帧将显示多次。例如,一帧要1/45妙,帧频为30fps,图形程序将每帧空闲1/30 - 1/45 = 1/90妙,即每帧显示时间1/3。(这个例子说明什么?没看懂,为什么帧频改为30fps,60才能说明问题嘛!)
  另外,视频刷新频率是固定的,可导致一些意想不到的性能问题。例如,如果显示器刷新频率为60次每秒,且要求帧频是恒定的,则帧频可以是60、30、20、15、12fps。这意味着如果编写一个应用程序,并逐渐加入新特性,最初对整体性能没有影响,帧频仍然可达到60fps;但加入后,系统不能在1/60妙内绘制好整个帧,帧频会从60fps降低到30fps,因为系统错过了第一次交换缓存的机会。当每帧的绘制时间超过1/30妙时,将放生类似的事情——帧频从30fps降低到20fps。
  如果场景的复杂程度与某个魔幻时间接近,由于偏差的随记性,有些帧的绘制将稍长些,有些稍短些,因此帧频将是无规律的,将导致视觉上的混乱。如不能简化场景来确保所有帧的绘制速度都足够快,最好加一段延迟,确保所有的帧都将失去缓存交换机会,以得到较低但恒定的帧频。
  运动就是重画加交换
  通常,对于每一帧,重新绘制整个缓存比判断哪些部分需要重新绘制更容易,三维模拟器应用更是如此。
  使用不同的变换重新绘制场景中的物体。如果非绘制操作涉及的重新计算量非常大,则可达到帧频常常会降低。然而,可以使用函数swap_the_buffers()执行后的空闲来完成这样的计算。
  OpenGL并没有提供swap_the_buffers()函数,因为并非所有硬件都支持这种特性:在任何情况下,这种特性都与窗口系统相关。

  《OpenGL编程指南》第一章,几乎是抄了一遍;今天打了好多字,起码不会虚度。配置好opengl类库,敲出第一个小例子:

View Code
 1 #include "stdafx.h"
2 #include <gl/glut.h>
3
4 void display(void) {
5 glClear(GL_COLOR_BUFFER_BIT);
6 glColor3f(1.0, 1.0, 1.0);
7 glBegin(GL_POLYGON);
8 glVertex3f(0.25, 0.25, 0.0);
9 glVertex3f(0.75, 0.25, 0.0);
10 glVertex3f(0.75, 0.75, 0.0);
11 glVertex3f(0.25, 0.25, 0.0);
12 glEnd();
13 glFlush();
14 }
15
16 void init(void) {
17 glClearColor(0.0, 0.0, 0.0, 0.0);
18 glMatrixMode(GL_PROJECTION);
19 glLoadIdentity();
20 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
21 }
22 int main(int argc, char* argv[])
23 {
24 glutInit(&argc, argv);
25 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
26 glutInitWindowSize(250, 250);
27 glutInitWindowPosition(100, 100);
28 glutCreateWindow("hello");
29 init();
30 glutDisplayFunc(display);
31 glutMainLoop();
32 return 0;
33 }

  

write by fgd

原文地址:https://www.cnblogs.com/wendao/p/ogl_start_learning.html