顶点着色器用于基于顶点的操作,例如通过矩阵变换位置、计算照明方程式以生成逐顶点的颜色以及生成或者变换纹理坐标。
变量 | 描述 |
---|---|
gl_VertexID | 输入变量,用于保存顶点的整数索引。highp 精度的整数变量 |
gl_InstanceID | 输入变量,用于保存实例化绘图调用中图元的实例编号。highp 精度的整数变量,通常情况下为 0 |
gl_Position | 输出变量,用于输出顶点作为的裁剪坐标。highp 精度的浮点变量 |
gl_PointSize | 用于指定点精灵的尺寸,单位为像素。highp 精度的浮点变量 |
gl_FrontFacing | 不由顶点着色器直接写入,而是根据顶点着色器生成的位置值和渲染的图元类型生成,它是一个布尔变量 |
顶点着色器中唯一的内建统一状态是窗口坐标中的深度范围,由内建统一变量名 gl_DepthRange 给出,该变量声明为 gl_DepthRangeParameters 类型的统一变量
struct gl_DepthRangeParameters {
highp float near; // near z
highp flaot far; // far z
highp float diff; // far - near
}
uniform gl_DepthRangeParameters gl_DepthRange;
在所有 ES 3.0 实现中,如下常量都有支持的最小值,但实际值需要使用指定接口查询。
类型 | 名称 | 最小值 | 描述 |
---|---|---|---|
const mediump int | gl_MaxVertexAttribs | 16 | 顶点着色器中属性的最大数量 |
const mediump int | gl_MaxVertexUniformVectors | 256 | 顶点着色器中统一变量的最大数量 |
const mediump int | gl_MaxVertexoutputVectors | 16 | 顶点着色器中输出向量的最大数量 |
const mediump int | gl_MaxTextureImageUnits | 16 | 顶点着色器中纹理单元的最大数量 |
const mediump int | gl_MaxCombinedTextureImageUnits | 32 | 顶点着色器和片段着色器中纹理单元最大数量的总和 |
上面我们知道 gl_MaxVertexUniformVectors 描述了顶点着色器统一变量的最大值,统一变量存储如下变量:
对于字面值,ES 3.0 规范规定不做任何常量传播。结果是一个字面值的多个实例将被计算多次,即我们应该声明相应的常数变量代替字面值,可避免同一个字面值计算多次。
如下一个顶点着色器:
#version 300 es
#define NUM_TEXTURES 2
uniform mat4 tex_matrix[NUM_TEXTURES];
uniform bool enable_tex[NUM_TEXTURES];
uniform bool enable_tex_matrix[NUM_TEXTURES];
in vec4 a_texcoord0; // available if enable_tex[0] is true
in vec4 a_texcoord1; // available if enable_tex[1] is true
out vec4 v_textcoord[NUM_TEXTURES];
void main() {
v_textcoord[0] = vec4(0.0, 0.0, 0.0, 1.0);
if (enable_tex[0]) {
if (enable_tex_matrix[0]) {
v_textcoord[0] = tex_matrix[0] * a_texcoord0;
} else {
v_textcoord[0] = a_texcoord0;
}
}
v_textcoord[1] = vec4(0.0, 0.0, 0.0, 1.0);
if (enable_tex[1]) {
if (enable_tex_matrix[1]) {
v_textcoord[1] = tex_matrix[1] * a_texcoord1;
} else {
v_textcoord[1] = a_texcoord1;
}
}
}
上例中字面值 0、1、0.0、1.0 的每次引用都会被计入统一变量存储,为了保证这些字面值只计数一次,可以使用常量变量代替,例如:
#version 300 es
#define NUM_TEXTURES 2
uniform mat4 tex_matrix[NUM_TEXTURES];
uniform bool enable_tex[NUM_TEXTURES];
uniform bool enable_tex_matrix[NUM_TEXTURES];
in vec4 a_texcoord0; // available if enable_tex[0] is true
in vec4 a_texcoord1; // available if enable_tex[1] is true
out vec4 v_textcoord[NUM_TEXTURES];
const int zero = 0;
const int one = 1;
void main() {
v_textcoord[zero] = vec4(float(zero), float(zero), float(zero), float(one));
if (enable_tex[zero]) {
if (enable_tex_matrix[zero]) {
v_textcoord[zero] = tex_matrix[zero] * a_texcoord0;
} else {
v_textcoord[zero] = a_texcoord0;
}
}
v_textcoord[one] = vec4(float(zero), float(zero), float(zero), float(one));
if (enable_tex[one]) {
if (enable_tex_matrix[one]) {
v_textcoord[one] = tex_matrix[one] * a_texcoord1;
} else {
v_textcoord[one] = a_texcoord1;
}
}
}
#version es 300
unidorm mat4 u_mvpMatrix // 把坐标从模型空间转换到裁剪空间的矩阵
layout(location = 0) in vec4 a_position; // 输入的位置值
layout(location = 1) in vec4 a_color; // 输入的颜色值
out vec4 v_color; // 输出的颜色值,将是片段着色器的输入值
void main() {
v_color = a_color;
gl_Position = u_mvpMatrix * a_position;
}
上例中的统一变量 u_mvpMatrix
引入了“模型-视图-投影(MVP)”矩阵的概念。顶点着色器的位置输入保存为物体坐标,而输出位置保存为裁剪坐标。MVP 矩阵是 3D 图形中进行这种变换的 3 个非常重要的变换矩阵的乘积:模型矩阵、试图矩阵和投影矩阵。
相关概念:
常见一个MVP矩阵产生的过程为:
private final float[] mProjectionMatrix = new float[16]; // 投影矩阵
private final float[] mModelMatrix = new float[16]; // 模型矩阵
private final float[] mViewMatrix = new float[16]; // 视图矩阵
private final float[] mViewProjectionMatrix = new float[16];
private final float[] mModelViewProjectionMatrix = new float[16]; // MVP矩阵
// 1.投影矩阵
// 以45度的视野创建一个投影矩阵,视锥体从z值为-1的位置开始,在z值为-10的位置结束
Matrix.perspectiveM(mProjectionMatrix, 0, 45, (float) width / (float) height, 1f, 10f);
// 2.视图矩阵
// 把眼睛设为(0,1.2,2.2)的位置,即眼睛在x-z平面三方1.2个单位,向后2.2个单位
Matrix.setLookAtM(mViewMatrix, 0, 0f, 1.2f, 2.2f, 0f, 0f, 0f, 0f, 1f, 0f);
// 3. 模型矩阵
// 初始化模型矩阵为一个单位矩阵
Matrix.setIdentityM(mModelMatrix, 0);
// 将模型沿着z轴平移-2个单位,使得我们可以看见它
Matrix.translateM(mModelMatrix, 0, 0f, 0f, -2f);
// 将模型绕着x轴旋转-60度
Matrix.rotateM(mModelMatrix, 0, -60, 1f, 0f, 0f);
// 4.MVP矩阵
// 将投影和视图矩阵相乘,并缓存到mViewProjectionMatrix中
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// 将模型矩阵和上述ViewProjectionMatrix矩阵相乘,即是MVP矩阵
Matrix.multiplyMM(mModelViewProjectionMatrix, 0, mViewProjectionMatrix, 0, mModelMatrix, 0);