在OpenGL中向shader传递信息
主要參考網頁 http://blog.csdn.net/racehorse/article/details/6634830
可先行參考OpenGL基本瞭解(四) (GLSL基本資料)
一个OpenGL程序可以用多种方式和shader通信。注意这种通信是单向的,因为shader的输出只能是渲染到某些目标,比如颜色和深度缓存。
OpenGL的部分状态可以被shader访问,因此程序改变OpenGL某些状态就可以与shader进行通信了。例如一个程序想把光的颜色传给shader,可以直接调用OpenGL接口,就像使用固定功能流水线时做的那样。
不过,使用OpenGL状态并不是设置shader中使用数据的直观方式。比如一个shader需要一个表示时间变化的变量来计算动画,在OpenGL状态中就没有现成的变量可用。
幸运的是,GLSL允许用户自定义变量,实现OpenGL应用程序与shader通信。
GLSL提供的两种类型修饰符(更多的类型将在后面提到):
·一致变量(Uniform)
·属性(Attribute)
在GLSL檔案中的例子VertexShader.glsl
uniform mat4 projection;
uniform mat4 modelView;
attribute vec4 vKPosition;
void main(void)
{
gl_Position = projection * modelView * vKPosition;
}
在shader中定义的变量如果用这两种类型修饰符,表示对shader来说,它们是只读的。下面将详细讲述怎样使用这些类型的变量。
还有一种将变量送给shader的方法:使用纹理。一个纹理不止可以表示一张图片,它还可以表示一个数组。事实上,你完全可以决定如何在shader中解释纹理数据,即使它真是一幅图片。
模型矩阵与视图矩阵的合体叫着模型-视图矩阵。在OpenGLES 1.1中,所有的顶点都先经过模型-视图矩阵作用,然后再由投影矩阵作用。而OpenGL ES 2.0中, 你可以任意变换, 但是常常也是按照模形-视图/投影的过程变换,至少得差不多。
在ES1.1中,当前变换可以用矩阵来表达,如下:
float projection[16] = { ... };
float modelview[16] = { ... };
glMatrixMode(GL_PROJECTION); //指定哪一个矩阵是当前矩阵, GL_MODELVIEW/GL_PROJECTION/GL_TEXTURE
glLoadMatrixf(projection);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(modelview);
***********************************
glMatrixMode(mode)说明
glMatrixMode设置当前矩阵模式:
GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作.
GL_PROJECTION,对投影矩阵应用随后的矩阵操作.
GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作.
在ES2.0中,并没有模形-视图矩阵,也没有glMatrixMode与glLoadMatrixf这样的方法。取而代之的是shaders中的 uniform变量。在后面我们会学到,uniforms是一种shader中用到的类型,我们可以简单的把它理解为shader不能改变的常數
加载方式如下:
float projection[16] = { ... };
float modelview[16] = { ... };
GLint projectionUniform = glGetUniformLocation(program, "Projection");
glUniformMatrix4fv(projectionUniform, 1, 0, projection);
GLint modelviewUniform = glGetUniformLocation(program, "Modelview");
glUniformMatrix4fv(modelviewUniform, 1, 0, modelview);
其中glUniformMatrix4fv函数作為传递数据之用。
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &World.m[0][0]); 第一个参数是第一个参数是shader uniform变量的位置索引
第二个参数是被赋值的矩阵的数目(因为 uniform变量可以是一个数组)。 通常為1
第三个参数表明在向uniform变量赋值时该矩阵是否需要转置。GL_TRUE => 需要轉置
最后一个参数就是传递给 uniform变量的pointer了。
原文說明
The commands glUniformMatrix{2|3|4|2x3|3x2|2x4|4x2|3x4|4x3}fv are used to modify a matrix or an array
of matrices. The numbers in the command name are interpreted as the dimensionality of the matrix. The
number 2 indicates a 2 x 2 matrix (i.e., 4 values), the number 3 indicates a 3 x 3 matrix (i.e., 9
values), and the number 4 indicates a 4 x 4 matrix (i.e., 16 values). Non-square matrix
dimensionality is explicit, with the first number representing the number of columns and the second
number representing the number of rows. For example, 2x4 indicates a 2 x 4 matrix with 2 columns and
4 rows (i.e., 8 values). If transpose is GL_FALSE, each matrix is assumed to be supplied in column
major order. If transpose is GL_TRUE, each matrix is assumed to be supplied in row major order. The
count argument indicates the number of matrices to be passed. A count of 1 should be used if
modifying the value of a single matrix, and a count greater than 1 can be used to modify an array of
matrices.
为何OpenGL中的好多方法都由f或fv结尾。许多方法(如glUniform*)可以是浮点-指针参数的方法,可以是整形参数 的方法,可是以其它类型参数的方法。OpenGL是C型的API,而C又不支持方法重载,所以每个方法得用不同的名字加以区分。表2.4 “OpenGL ES 方法后缀”,是方法的后缀的解释。随便说一下,v表示是一个指针型参数(pointer *)。
表2.4 OpenGL ES方法后缀
后缀
|
类型
|
i
|
32位整形
|
x
|
16位定点
|
f
|
32位浮点
|
ub
|
8位无符号byte
|
ui
|
32位无符号整形
|
数据类型和变量
下面是GLSL中的基本数据类型:·float
·bool
·int
浮点类型与C中类似,布尔类型可以为true或false。这些基本类型可以组成2、3或4维向量,如下所示:
·vec{2,3,4} a vector of 2,3,or 4 floats
·bvec{2,3,4} bool vector
·ivec{2,3,4} vector of integers
GLSL还包括2×2、3×3或4×4型矩阵,因为这些矩阵类型在图形处理中很常用:
·mat2
·mat3
·mat4
此外,还有一组用来实现纹理访问的特殊类型,它们被称为采样器(sampler),在读取纹理值(也称为纹素texel)时用到。下面就是纹理采样用到的数据类型:
·sampler1D – for 1D textures
·sampler2D – for 2D textures
·sampler3D – for 3D textures
·samplerCube – for cube map textures
·sampler1DShadow – for shadow maps
·sampler2DShadow – for shadow maps
參考使用例
struct dirlight // type definition
{
vec3 direction;
vec3 color;
};
dirlight d1;
dirlight d2 = dirlight(vec3(1.0,1.0,0.0),vec3(0.8,0.8,0.4));
vec4 a = vec4(1.0,2.0,3.0,4.0);
float posX = a.x;
float posY = a[1];
vec2 posXY = a.xy;
float depth = a.w
關於 shader的数据类型和变量就必須參考
http://blog.csdn.net/racehorse/article/details/6634830
变量修饰符
修饰符给出了变量的特殊含义,GLSL中有如下修饰符:
·const – 声明一个编译期常量。
·attribute– 随不同顶点变化的全局变量,由OpenGL应用程序传给顶点shader。这个修饰符只能用在顶点shader中,在shader中它是一个只读变量。
·uniform– 随不同图元变化的全局变量(即不能在glBegin/glEnd中设置),由OpenGL应用程序传给shader。这个修饰符能用在顶点和片断shader中,在shader中它是一个只读变量。
·varying –用于顶点shader和片断shader间传递的插值数据,在顶点shader中可写,在片断shader中只读。
一致变量(Uniform Variables)
不同于顶点属性在每个顶点有其自己的值,一个一致变量在一个图元的绘制过程中是不会改变的,所以其值不能在glBegin/glEnd中设置。一致变量适合描述在一个图元中、一帧中甚至一个场景中都不变的值。一致变量在顶点shader和片断shader中都是只读的。
首先你需要获得变量在内存中的位置,这个信息只有在连接程序之后才可获得。注意,对某些驱动程序,在获得存储位置前还必须使用程序(调用glUseProgram)。
获取一个一致变量的存储位置只需要给出其在shader中定义的变量名即可:
GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
0.2,0.2,0.4,1.0,
0.1,0.1,0.1,1.0};
loc1 = glGetUniformLocation(p,"specIntensity");
glUniform1f(loc1,specIntensity);
loc2 = glGetUniformLocation(p,"specColor");
glUniform4fv(loc2,1,sc);
loc3 = glGetUniformLocation(p,"t");
glUniform1fv(loc3,2,threshold);
loc4 = glGetUniformLocation(p,"colors");
glUniform4fv(loc4,3,colors);
属性变量(Attribute Variables)
在前一节提到,一致变量只能针对一个图元全体,就是说不能在glBegin和glEnd之间改变。
如果要针对每个顶点设置变量,那就需要属性变量了。事实上属性变量可以在任何时刻更新。在顶点shader中属性变量是只读的。因为它包含的是顶点数据,所以在片断shader中不能直接应用。
与一致变量相似,首先你需要获得变量在内存中的位置,这个信息只有在连接程序之后才可获得。注意,对某些驱动程序,在获得存储位置前还必须使用程序。
GLint glGetAttribLocation(GLuint program,char *name);
参数:
program – the handle to the program.
name – the name of the variable
void glVertexAttrib1f(GLint location, GLfloat v0);
void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);
或者
GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);
参数:
location – the previously queried location.
v0,v1,v2,v3 – float values.
v – an array of floats.
loc = glGetAttribLocation(p,"height");
易变变量(Varying Variables)
前 面说过,shader包括两种类型:顶点shader和片断shader。为了计算片断的值,往往需要访问顶点的插值数据。例如,当使用逐片断光照时,我 们需要知道当前片断的法线,但是在OpenGL中只为每个顶点指定了法线。顶点shader可以访问这些法线,而片断shader不能,因为法线是 OpenGL程序作为属性变量指定的。
顶 点变换后的数据移动到流水线的下一个阶段,在这个阶段通过使用连接信息,生成了所有图元并完成片断化。对每个片断,有一组变量会被自动进行插值并提供给片 断shader,这些都是固定功能。片断的颜色就是这么处理的,到达片断shader的颜色就是组成图元的顶点颜色插值的结果。
像片断shader接收到的这种插值产生的变量,就是“易变变量”类型。GLSL包含一些预先定义的易变变量,例如前面提到的颜色。用户也可以自己定义易变变量,它们必须同时在顶点shader和片断shader中声明:
varying float intensity;
一个易变变量必须先在顶点shader中声明,然后计算每个顶点的变量值。在片断shader中,接收这个变量通过插值得到的结果,注意此时这个变量是只读的。
语句和函数
控制流语句
与C语言类似,GLSL中有类似if-else的条件语句,for,while,do-while等循环语句。
vec4 toonify(in float intensity)
{
vec4 color;
if (intensity > 0.98)
color = vec4(0.8,0.8,0.8,1.0);
else if (intensity > 0.5)
color = vec4(0.4,0.4,0.8,1.0);
else if (intensity > 0.25)
color = vec4(0.2,0.2,0.4,1.0);
else
color = vec4(0.1,0.1,0.1,1.0);
return(color);
}
Shader-Centric View of OpenGL (VS = Vertex Shader, FS = Fragment
Shader)”.
Floating-point Precision in 3rd Generation Devices


沒有留言:
張貼留言