OpenGL编程指南2D部分【上】

来源:互联网 发布:奶瓶linux系统下载 编辑:程序博客网 时间:2024/05/21 15:45

自己用Laravel写的小博客和CSDN的博客以后同步更新:
OpenGL编程指南2D部分【上】

1. OpenGL 概述

opengl是一套图形API,指示显卡进行显示操作,若无显示硬件则采用软件实现。

opengl渲染管线:

顶点数据->着色器->光栅->显示

创建对象:首先使用glGen*创建一个名字,再使用glBind*创建并且激活对象,将其绑定到名字上。

顶点对象:保存顶点信息。

缓存对象:顶点对象管理的数据存储在缓存对象中,是显存的一块区域。

每个大于3.1的opengl渲染管线中至少需要vertex shader和fragment shader

2. 着色器基础

杂项

  • 现代opengl严重依赖shader,若无shader便只能清除窗口。
  • double后面必须加LF。
  • swizzle: vec3 a = color.rgb

可编程管线的阶段

  • 顶点着色 vertex shading
  • 细分着色 tessellation shading
  • 几何着色 geometry shading
  • 片元着色 fragment shading
  • 计算着色 compute shading

基本数据类型

  • float
  • double
  • int
  • uint
  • bool
  • 不透明类型

聚合数据类型

  • [-diub]vec[234]
  • [-d]mat[234]x[234]

访问聚合数据类型

  • 位置相关 = x,y,z,w
  • 颜色相关 = r,g,b,a
  • 纹理相关 = s,t,p,q
  • 直接用数字索引

存储限定符

  • const
  • in
  • out
  • uniform
  • buffer - shader可读写
  • shared - 计算着色器中使用,本地工作组共享

函数参数限定符

  • in - 默认
  • const in
  • out - 无输入值
  • inout - 相当于&

特殊流控制语句

  • discard - 丢弃当前片元,终止着色器执行,只能用于fragment shader

计算不变性

GLSL中,通过常量调用函数会被编译器在cpu直接计算出来,所以和变量调用函数结果可能不同,
这种结果无法保证不变。

不同的shader中,可以通过对变量设置invariant标识符,保证相同计算式计算结果完全相同,
也可以通过#pragma STDGL invariant(all)来完成这项工作。

precise是一种更精确的标识符,会对计算式进行诸多限制,普通来说invariant已足够。

编译器控制

  • #pragma optimize(on) 着色器优化
  • #pragma debug(on) 开启调试模式

Uniform变量

在程序中指定,作用于shader的变量,通过glGetUniformLocation获取位置后,调用
glUniform{type}进行写入,可在shader中使用。

Uniform变量块

用于在多个shader program之间共享uniform变量。

首先使用glGetUniformBlockIndex获取块索引,使用glGetActiveUniformBlockiv获取大小,
然后使用glBindBufferRange/glBindBufferBase绑定块与缓存对象,初始化缓存中的数据。

多个program以共享方式使用块的话,我们需要将名称绑定在缓存上,使用glUniformBlockBinding
在glLinkProgram之前调用。

如果采用默认布局,需要通过glGetUniformIndices来获取变量位置,方便在缓存中存储数据

Uniform变量块布局限定符

  • shared 默认,多程序共享
  • packed 占用空间最小,禁止共享
  • std140
  • std430
  • row_major 以行为主储存mat
  • column_major 以列为主储存mat,默认

Buffer块

和uniform块相似,shader可以修改其内容,可在链接后决定其大小。

In/out块

即输入输出接口,前一shader输出与后一shader输入必须相同。

创建program

  1. 创建shader,导入源码,编译并查错。
  2. 创建program,导入shader,链接并查错。

使用完的shader对象可以标记为可删除,当没有program链接时会被删除。

子程序

可以选择渲染时执行哪一个程序。首先通过subroutine定义函数类型,然后定义几个
当前类型的函数,再定义一个subroutine uniform类型的变量指示哪一个会被执行。
在程序中调用glGetSubroutineUniformLocation获取uniform的位置,
调用glGetSubroutineIndex获取子函数索引,然后通过glUniformSubroutinesuiv指定执行。

独立着色器对象

可将多个program的不同阶段合并到同一pipeline当中。

3. OpenGL绘制方式

图元

  • 点,可设置大小
  • 线段,环线,可设置宽度
  • 三角形,条带,扇面

正反面

  • 通过glPolygonMode可设置正反面不同的绘制方法。
  • 通过glFrontFace设置哪一面为正面,默认右手螺旋为正。
  • 通过glCullFace直接抛弃某个面

缓存

通过glGenBuffer创建一个名称,再用glBindBuffer根据其用途创建空间并且激活。
然后就可以利用glBufferData向其中存入数据。

可通过glBufferSubData对部分数据进行操作,可通过glClear[Sub]Data和glCopy[Sub]Data
和glGet[Sub]Data操作数据。

还可以通过glMapBuffer获取指针,直接对地址操作。然后通过glUnmapBuffer释放指针。
这种方式在释放指针后将直接将数据交由OpenGL处理,效率更高。

可通过glInvalidateBuffer[Sub]Data通知opengl丢弃无用的数据。

顶点规范

glVertexAttrib[type]Pointer函数通知opengl如何使用缓存中的数据,
对于大值的数据,使用整形顶点提高效率,
默认会将任意类型数据转化为float,若用其他类型,则需要对应的type

压缩格式可以将一个顶点压缩于一个32位整数中

如果不使用glEnableVertexAttribArray,则属性会使用默认数据,
通过glVertexAttrib[type]来设置默认属性,简化重复操作。

绘制命令

glDrawArray根据数组顺序绘制顶点,glDrawElements根据数组索引绘制顶点。
glDrawElements被认为是一个高效率的方法,节约了缓存,提高速度。

glDrawArraysIndirect是间接绘制,绘制的命令存在于GL_DRAW_INDIRECT_BUFFER
缓存中,索引绘制也有间接版本。

glMultiDrawArrays通过对数组的调用,绘制大量的图像,提高效率。
同样,索引绘制也有multi版本。

数组绘制和索引绘制都有间接multi版本。

图元重启动

打断正在绘制的符合索引条件的图元。

多实例渲染

可将同一个图元绘制很多遍,只有部分属性不同,提高效率。
通过glVertexAtrribDivisor控制属性变化频率,通过glVertexAttribPointer设置不同的属性。
shader中,可以通过gl_InstanceID获取当前instance的索引

VAO使用

  1. 创建VAO,并且绑定。
  2. 使用glGetAttribLocation获取输入参数索引。
  3. 通过glVertexAttribPointer指定buffer中的数据如何用作某一个输入参数。
  4. 使用glEnableVertexAttribArray启用某一个输入参数。
  5. 调用draw函数。
0 0
原创粉丝点击