OpenGL ES 3.0可编程管线如下图所示。其中阴影部分的顶点着色器和片段着色器是可编程阶段。
本章将举几个常用例子,例如:模型视图和投影矩阵变换顶点位置、生成逐顶点漫反射和反射颜色的顶点照明、纹理坐标生成、顶点蒙皮和位移贴图。
顶点着色器概述
顶点着色器的输入包括:
1、属性:用顶点数组提供的逐顶点数据
2、统一变量和统一变量缓冲区:顶点着色器使用的不变数据
3、采样器:代表顶点着色器使用的纹理的特殊统一变量类型
4、着色器程序:顶点着色器程序源代码或者生成的可执行文件
顶点着色器的输出:图元光栅化时,为了生成的片段需要计算这些输出变量。
顶点着色器内建变量
内建变量可以分成
1、特殊变量(顶点着色器的输入输出)
2、统一状态(深度范围)
3、规定最大值(属性数量、顶点着色器输出变量数量和统一变量数量)
内建特殊变量
OpenGL ES 3.0有内建的特殊变量。
gl_VertexID // 顶点的整数索引
gl_InstanceID // 实例化绘图调用中图元的实例编号
gl_Position // 输出顶点位置的裁剪坐标
gl_PointSize // 以像素表示的点精灵尺寸
gl_FrontFacing // 根据顶点着色器生成的位置值和渲染的图元类型生成的
内建统一状态
顶点着色器内可用的唯一内建统一状态是窗口坐标中的深度范围。
struct gl_DepthRangeParameters {
highp float near; // near Z
highp float far; // far Z
highp float diff; // far – near
}
uniform gl_DepthRangeParameters gl_DepthRange;
内建常量
// 指定的顶点属性的最大数量
const mediump int gl_MaxVertexAttribs = 16;
// 可以使用的的vec4统一变量数目的最大数量
const mediump int gl_MaxVertexUniformVectors = 256;
// 输出向量的最大值
const mediump int gl_MaxVertexOutputVectors = 16;
// 可用的纹理单元的最大数量
const mediump int gl_MaxVertexTextureImageUnits = 16;
// 顶点和片段着色器中可用的纹理单元最大数量的总和
const mediump int gl_MaxCombinedTextureImageUnits = 32;
精度限定符
指定精度的关键字是lowp、mediump和highp。
precision highp float;
指定所有float数变量的默认精度为高精度。
顶点着色器中的统一变量限制数量
任何兼容OpenGL ES 3.0实现必须支持的gl_MaxVertexUniformVectors的最小值为256个vec4项目。
统一变量存储用于存储如下变量:
1、用统一变量限定符声明的变量
2、常数变量
3、字面值
4、特定于实现的常量
顶点着色器示例
矩阵变换
下述代码是使用矩阵变换位置的顶点着色器:
#version 300 es
// uniforms used by the vertex shader
uniform mat4 u_mvpMatrix; // matrix to convert position from
// model space to clip space
// attribute inputs to the vertex shader
layout(location = 0) in vec4 a_position; // input position value
layout(location = 1) in vec4 a_color; // input color
// vertex shader output, input to the fragment shader
out vec4 v_color;
void main() {
v_color = a_color;
gl_Position = u_mvpMatrix * a_position;
}
上述的统一变量u_mvpMatrix的形式引入了模型-视图-投影(MVP)矩阵的概念。
模型矩阵:将物体坐标变换为世界坐标
视图矩阵:将世界坐标变换为眼睛坐标
投影矩阵:将眼睛坐标变换为裁剪坐标
顶点着色器中的照明
这个小节主要包括直射光和聚光灯两种种照明。
生成纹理坐标
球面图纹理坐标生成:
// position is the normalized position coordinate in eye space.
// normal is the normalized normal coordinate in eye space.
// This function returns a vec2 texture coordinate.
vec2 sphere_map ( vec3 position, vec3 normal ) {
reflection = reflect ( position, normal );
m = 2.0 * sqrt ( reflection.x * reflection.x + reflection.y * reflection.y + ( reflection.z + 1.0 ) * ( reflection.z + 1.0 ) );
return vec2(( reflection.x / m + 0.5 ), ( reflection.y / m + 0.5 ) );
}
立方体图纹理坐标生成:
// position is the normalized position coordinate in eye space.
// normal is the normalized normal coordinate in eye space.
// This function returns the reflection vector as a vec3 texture
// coordinate.
vec3 cube_map ( vec3 position, vec3 normal ) {
return reflect ( position, normal );
}
顶点蒙皮
顶点蒙皮用于平滑多边形之间的连接点,这通过向每个顶点应用具有相应权重的附加变换矩阵来实现。常用于3D游戏中的角色模型。计算公式如下图:
n是用于变换顶点的矩阵数量
P是顶点位置
P'是变换蒙皮后的位置
N是顶点的法线
N'是变换蒙皮后的法线
Mi是每个顶点第i个矩阵相关的矩阵
变换反馈
变换反馈模式允许将顶点着色器的输出捕捉到缓冲区对象中。然后,输出缓冲区可以作为后续绘图调用中顶点数据的来源。这种方法用于再GPU上执行动画而无需任何CPU干预。
要指定变换反馈模式期间捕捉的一组顶点属性,可以使用如下命令:
void glTransformFeedbackVaryings(GLuint program,
GLsizei count,
const char** varyings,
GLenum bufferMode)
顶点纹理
OpenGL ES 3.0支持顶点着色器中的纹理查找操作。
位移贴图技术的典型应用之一就是渲染地形和水面。
将OpenGL ES 1.1顶点管线作为ES 3.0顶点着色器
实现OpenGL ES 1.1顶点管线的如下固定功能:
1、再必要时将法线和位置变换到眼睛,还执行法线的比例调整或者规范化。
2、为8个光源计算顶点照明方程,每个顶点拥有双面照明和彩色材料。
3、换纹理坐标。
4、计算传递给片段着色器的雾化因子。
5、计算逐顶点用户裁剪平面因子。
6、将位置变换到裁剪空间。
小结
本章用几个例子高度概括了顶点着色器融入管线和再定点着色器中执行变换、照明、蒙皮和位移贴图的方法。