纯属个人片面感触,OpenGL spec 运用甚至发明的一些术语非常令人费解,就比方 shader,字面含义与专业功用有所疏离。Shade 作为名词,意思是不同色彩之间的过渡或突变,典型运用是一部电影名”50 Shades of Grey“。显然在 OpenGL 中 shade 是作动词用的,理解为发生作为名词的 shades 的动作/进程,那么,关于 OpenGL 烘托流水线中 Fragment Shader 阶段而言它是适宜的,然而对 Vertex Shader,则很难让人在脑子里就二者构成关联–等等!,fragment 不也正是另一个虚头八脑的术语么?

在 GLSL 中界说了这样几个所谓的 Storage Qualifier:const, attribute, uniform, varying。第一个沿用 C ,没毛病。attribute 经过前几天的折腾,已接受:变量绑定到 vertex attribute array,作为 vertex shader 的输入,只能在 vertex shader 中运用。但是,uniformvarying?黑人表情。

varying

说,varying 变量是从 vertex shader 的输出,输入 fragment shader。这课的第一个示例程序,用 varying 在 vertex shader 中界说一个色彩变量,给它写死一个值;转到 fragment shader 中,把传过来的色彩直接赋给 fragment,成为屏幕上终究呈现出来的色彩。Vertex shader:

...
varying mediump vec4 a_color;
void main()
{
    ...
    a_color = vec4(.5, 0, 0, 1);
}

以及 fragment shader:

...
precision mediump float;
varying vec4 a_color;
void main()
{
    gl_FragColor = a_color;
}

关于 varying,只要一点需求说明:在 vertex shader 和 fragment shader 中有必要声明严厉共同,包含类型和精度。

GLSL 规则整数和浮点型变量有高中低 3 档精度:highp, mediump, lowp。不同精度的运算成本和结果的…精度不同。关键:

  • Vertex shader 的缺省精度为 highp;fragment shader 没有缺省精度,每个变量有必要显式声明
  • 能够以 precision <precision> <type>; 的方法声明 shader 的默认精度,例如上面 fragment shader 声明 float 类型默认为 mediump,因而在下面声明 varying 变量时省略了精度

上面 vertex shader 中 varying 变量显式声明为 mediump,而 fragment shader 中经过默认精度的方法使得 varying 也是 mediump,二者共同,满足 GLSL 的要求。

完好代码在 gitlab.com/sihokk/lear…

uniform

第二个例程演示 uniformuniform 变量在 shader 中只读,vertex shader 和 fragment shader 都能够访问。例程在 fragment shader 中界说了一个 uniform 色彩变量,该色彩赋值给 fragment 成为屏幕绘制色彩。经过在程序中修正 uniform 的值,发生色彩变化的运转效果。

Fragment shader:

...
precision mediump float;
uniform vec4 a_color;
void main()
{
    gl_FragColor = a_color;
}

程序代码:

static void render()
{
    glClear(GL_COLOR_BUFFER_BIT);
    GLuint prog = ...
    GLint uniform_color = glGetUniformLocation(prog, "a_color");
    GLfloat green = (GLfloat)sin(SDL_GetTicks() / 1000.0) / 2   .5f;
    glUniform4f(uniform_color, 0, green, 0, 1);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
}

这儿将系统时间戳转换到 [0, 1] 区间的一个值,作为色彩的 G 通道重量。

首要经过 glGetUniformLocation() 获得 shader 中 uniform 的一个标识,然后调用 glUniform*() 函数对其赋值。这儿调用 glUniform4f() 接收 4 个 float 型参数,将依次赋值给 uniform 色彩变量的 RGBA 重量。

有一点需求着重:调用 glUniform*() 前有必要存在“当时 program”,即:现已调用过 glUseProgram() 将某个有效的 program 投入运用。ES spec 声称 uniform 是 program local 的数据,我是这样理解的:调用 glUniform*() 设置 uniform 的值,直接写入了 program,不像 attribute 那样是保存为 OpenGL 状况,而当 shader 执行时,从 OpenGL 状况中读取数据。

程序运转时,正方形色彩反复绿色突变(2^8 Shades of Green?)。完好代码在 gitlab.com/sihokk/lear…

Rasterizer 插值

比方绘制一个三角形,程序输入给 vertex shader 的只是 3 个极点的特点(如:坐标、色彩…),Rasterizer 却生成了三角形所能覆盖的屏幕像素范围内的很多个“点”,称为 fragment,包含三角形的 3 条边上以及内部的所有点。这些点的特点(再次:包含坐标、色彩…),rasterizer 是用简略的线性插值算法计算出来的。

例如,指定三角形 3 个极点的色彩分别是红绿蓝,rasterizer 终究发生的完好图形将是像下面这样的突变色:

OpenGL ES 2.0 笔记 #4:Shaders

极点特点数据界说是:

const GLfloat vertices[] = {
    // Position (x, y) , Color (r, g, b)
    -.5f, -.5f, 1.f, 0, 0, //
    .5f, -.5f, 0, 1.f, 0, //
    0, .5f, 0, 0, 1.f, //
};

共 3 个极点,每个极点包含 5 项数据,包含坐标(x/y)和色彩(r/g/b)。Vertex shader 中界说了 2 个 attribute,分别是极点坐标和色彩:

...
attribute vec4 a_pos;
attribute mediump vec4 a_color;
varying mediump vec4 vertex_color;
void main()
{
    gl_Position = a_pos;
    vertex_color = a_color;
}

看到色彩 attribute 经过 varying 传递给 fragment shader。

程序中将这 2 个 attribute 绑定到 VBO:

GLint attr_pos = glGetAttribLocation(prog, "a_pos");
GLint attr_color = glGetAttribLocation(prog, "a_color");
const GLsizei stride = 5 * sizeof(GLfloat);
glEnableVertexAttribArray(attr_pos);
glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(attr_color);
glVertexAttribPointer(attr_color, 3, GL_FLOAT, GL_FALSE, stride, (void *)(2 * sizeof(GLfloat)));

坐标和色彩保存在同一个 attribute array 中,也即同一个 VBO。每个极点包含 5 项数据,因而 stride 便是 5 项数据的字节数(第 4 行)。

坐标数据位于最初,因而偏移量为 0(第 7 行);而色彩数据则需求偏移坐标 x/y 2 项数据的字节数(第 10 行)。

完好程序代码:gitlab.com/sihokk/lear…