纯属个人片面感触,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 中运用。但是,uniform
?varying
?黑人表情。
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
第二个例程演示 uniform
。uniform
变量在 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 终究发生的完好图形将是像下面这样的突变色:
极点特点数据界说是:
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…