一、类型限定符:
const, in, out, uniform
1、in: 指定变量为着色器阶段的一个输入,输入可能是顶点属性(用于顶点着色器)或插值变量(用于片段着色器).
片段着色器可进一步限制其输入值,但要和in组合使用才有效:
centroid: 在打开多点采样时,强迫一个片段输入变量的采样位于图元像素的覆盖区域内。
smooth: 以透视校正的方式插值片段输入变量。
flat: 不对片段输入插值。
noperspective: 线性插值片段变量。
2、out: 指定变量为着色器阶段的一个输出.
顶点着色器可以使用centroid关键字限定其输出值,但必须有一个匹配的centroid片段着色器输入。
3、uniform: 指定这个值从应用程序传递个着色器,并在一个特定的图元中保持为常数值。uniform变量是由顶点着色器和片段着色器
共享的,必须声明为全局变量。
eg: uniform vec4 baseColor;
在着色器中,可以通过名字来引用baseColor, 但是为了在应用程序中设置它的值,需要一些额外工作。当GLSL编译器连接到着色
器程序后,它会创建一个表格,其中包含了所有的uniform变量。为了在;应用程序中设置baseColor的值,需要获取baseColor在表
中的索引值:
GLint glGetUniformLocation(GLuint program, const char* name);
获取了uniform变量的相关索引值,就可以设置这个变量的值:
void glUniform2iv(GLuint location TYPE value);
void glUniform3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *values);
void glUniformMatrix3fv(GLint location, GLsizei count,
GLboolean transpose, const GLfloat *values);
void glUniformMatrix2X3fv(GLint location, GLsizei count,
GLboolean transpose, const GLfloat *values);
//若transpose是GL_TRUE, values是按行主序指定,若是GL_FALSE,values是按列主序指定的。
eg:
GLint timeLoc; GLfloat timeValue; timeLoc = glGetUniformLocation(program, "time"); glUniform1f(timeLoc, timeValue);二、多个着色器程序使用同一个uniform值:
1、在着色器中指定uniform变量:
uniform Matrices{ //除了采样器,所有类型都可放在uniform块中;have to全局uniform块
mat4 ModelView;
mat4 Projection;
mat4 Color; //注意分号
};
uniform块的布局限定符:
1shared:指定uniform块在多个程序间共享(默认的共享设置)
2)packed: 布局uniform块以使其使用的内存最小化,这通常不允许跨程序共享
3)std140: 为uniform块使用OpenGL规范中描述的默认布局
4)row_major: uniform块中的矩阵按照行主序的方式存储
5)column_major: 矩阵按照列主序的方式存储(默认的排序)
eg:
//指定一个单个的uniform块共享,且按照行主序的方式存储矩阵:
layout (shared, row_major) uniform{...}; //句末分号
//影响到互殴uniform块的布局:
layout (packed, column_major) uniform;
2、访问在uniform块中声明的uniform变量:
在两个uniform块中声明具有相同名称的两个变量将会导致错误,但当访问一个uniform变量时,没必要使用uniform块名。
1)找到指定的uniform块中的各个uniform变量在着色器中的偏移量,先得找到块的索引:
GLuint glGetUniformBlockIndex(GLuint program, const char* uniformBlockName);
//若uniformBlockName不是program的一个有效uniform块,将返回GL_INVALID_INDEX
要初始化与uniform块相关的一个缓冲区对象,需要使用glBindBuffer()吧缓冲区对象绑定到GL_UNIFORM_BUFFER目标
初始化了一个缓冲区对象后,需要确定从着色器中留出多大空间来容纳指定的uniform块中的变量:
glGetActiveUniformBlockiv()请求GL_UNIFORM_BLOCK_DATA_SIZE,返回编译器生成的块的大小。
2)获取uniform块索引后,需要把一个帧缓冲区对象和该块联系起来:
void glBindBufferRange(GLenum target, GLuint index, GLuint buffer,
GLintptr offset,GLsizeiptr size);
void glBindBufferBase(GLenum target, GLuint index, GLuint buffer);//所有的缓冲区存储都用于uniform块
//target: GL_UNIFORM_BUFFER(用于uniform块),GL_TRANSFORM_FEEDBACK_BUFFER(用于变换反馈)
指定一个特定名称的uniform块绑定到一个缓冲区对象,在调用glLinkProgram()之前调用glUniformBlockBind():
GLint glUniformBlockBind(GLuint program, GLuint uniformBlockIndex, Gluint uniformBlockBinding);
//如果有多个着色器程序要共享一个uniform快,可采用此方法,它避免了为每个程序分配一个不同的块索引。
3)uniform变量在一个具名的uniform块中的布局由指定的布局限定符来控制,这在编译和连接uniform块的时候进行。如果使用默认的
布局指定,需要确定uniform块中的每个变量的offset和数据存储size:
//获取一个特定的具名uniform变量的索引:
void glGetUniformIndices(Gluint program, GLsizei uniformCount,
const char** uniformNames,GLuint *uniformIndices);
//获取这个特定索引的offset和size:
void glGetActiveUniformsiv(GLuint program?, GLsizei uniformCount?, const GLuint *uniformIndices?,
GLenum pname?, GLint *params?);
三、计算不变性:
GLSL并不保证不同的着色器中的两个相同的计算将产生完全相同的结果,使用invariant关键字,强制在着色器之间实行这种类型
的不变性。invariant限定符可以应用于顶点着色器的任何输出varying变量:
invariant gl_Position;
invariant centroid varying vec3 color;
//varying变量用于把顶点着色器的数据传递给片段着色器,不变性变量必须在顶点和片段着色器中都声明为invariant
四、GLSL函数的访问限定符:
GLSL不能返回数组,不存在指针和引用的概念。函数的参数访问限定符:
in: 值复制到函数中,默认。
const in: 只读,复制到函数中。
out: 值从函数中复制出来,在传递给函数之前未初始化。
inout: 值复制到函数中,并从函数中复制出来。
五、GLSL支持在顶点着色器(可选)和片段着色器(必须)中使用纹理对象。
为了使用纹理图像,GLSL把一个在OpenGL应用程序中配置的活动纹理单元与着色器中的一个变量相关联。这个变量允许着色器
程序访问纹理图像的数据,相关的纹理图像的维数必须与采样器的类型相匹配。采样器名称:
[is]smapler[123]D //访问1/2/3D纹理图像
usample[123]D
[is]samplerCube //访问立方体纹理图像(对于反射贴图)
usamplerCube
[is]sampler[12]DArray //访问1/2D纹理图像的一个数组
usampler[12]DArray
[is]sampler2DRect //访问一个2D纹理矩形
usampler2DRect
sampler[12]DShadow //访问1/2D阴影纹理
samplerCubeShadow //访问立方体阴影纹理
sampler1/2DArrayShadow //访问1/2阴影纹理的一个数组
sampler2DRectShadow //访问2D阴影纹理矩形
[is]samplerBuffer //访问纹理缓冲区
usamplerBuffer
采样器必须在着色器中声明为uniform变量,它们的赋值必须来自OpenGL应用程序。可作为函数参数。
采样器在着色器中使用之前必须分配一个纹理单位,并且只能通过glUniform1i()、glUniform1iv()初始化(把采样器应该
使用的纹理单位的索引作为参数)。
eg:
GLint texSampler; texSampler = glGetUniformLocation(program, "tex "); glUniform1i(texSampler, 2); //设置"tex " 使用GL_TEXTURE2当在GLSL着色器内部对一幅纹理图像进行采样时,需要使用已经声明并与一个纹理单位相关联的采样器变量。
eg: //在一个GLSL着色器内部对纹理进行采样
uniform sampler2D tex;
void main(){
gl_FragColor = gl_Color * texture2D(tex, gl_TexCoord[0].st);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
时间: 2024-10-24 19:32:33