一、GL SL (shading language)
是一中类似C的语言,包含了专门针对向量和矩阵操作的有用特性。
着色器代码编写,总是以版本声明开始,然后是输入和输出变量的列表,uniform和Main函数。
结构如下:
#version version_number
in type in_variable_name;
in type in_variable_name;
out type out_variable_name;
uniform type uniform_name;
int main()
{
// Process input(s) and do some weird graphics stuff
...
// Output processed stuff to output variable
out_variable_name = weird_stuff_we_processed;
}
vertex shader中,每个输入变量也叫顶点属性(Vertex Attribute)。顶点属性是有上限的(第一个三角形介绍的位置、颜色、法向量、纹理等顶点属性),它一般由硬件来决定。
OpenGL确保至少有16个包含4分量的顶点属性可用,但有的硬件允许更多的顶点属性,可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限:
GLint nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes
<< std::endl;
- [ 1] 要么就说最多输入16个顶点属性,怎么还16个属性包含4分量呢,4分量是什么啊?是坐标的维度?
二、GLSL 数据结构
数据结构方面,GLSL就是2个容器类,vector、matrices
GLSL也允许使用rgba描述颜色,或是使用stpq访问纹理坐标相应的分量。
1、Vector:
• vecn: the default vector of n floats.(常用,vecn.x访问x)
• bvecn: a vector of n booleans.
• ivecn: a vector of n integers.
• uvecn: a vector of n unsigned integers.
• dvecn: a vector of n double components.
可以对容器类的数据进行重组(swizzling),如下:
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec4 result = vec4(someVec, 0.0f, 0.0f);
vec4 otherResult = vec4(result.xyz, 1.0f);
三、shader的输入和输出
1、为什么vertex shader 与 fragment shader 不同?
因为,vertex不同在他的输入,理由:
vertex是直接接收vertex data,而vertex data 在CPU中的布局方式用的是location 标记(layout location= 0),这个标记可以配置CPU上的vertex属性。
vertex shader 需要对输入的 vertex data 进行location标记,才能跟这个data建立联系。
- [2 ] 我不知道你到底是要标记在CPU上vertex数据的布局,还是只配置CPU上vertex 缓冲区上的属性。
因为,fragment不用在他的输出需要一个vec4 的颜色变量。理由:
fragment shader的目的就是产生最终的输出颜色,如果不指定一个输出颜色,那么就会渲染成黑色(白色)
2、不同shader怎么实现数据交换?
必须在发送方shader 定义output,接收方shader 定义input。这样OpenGL才会在链接 shader program时 传输相同的数据类型,注意二者定义的变量名必须相同。
实现代码:
//vertex
#version 420 core
layout (location = 0) in vec3 position;
out vec4 vertexColor;
void main()
{
gl_Position = vec4(position, 1.0);
vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f);
}
//fragment
#version 420 core
in vec4 vertexColor;
out vec4 color;
void main()
{
color = vertexColor;
}
3、uniform是什么啊?
是组成一个GLSL的一部分,是用来把跑在CPU程序上的数据送到GPUshader 中的 一种数据传输方式。
类型——global,说明这个uniform是存在于单个shader程序中,能被shader程序的 各个阶段的shader访问。
注意:uniform定义了就必须用,不然很傻逼的报错。
要往uniform里面加数据,不简单。步骤如下:
1、找到shader中,uniform的属性标号,有了标号就可以修改值
2、不是传输单个颜色值,而是让颜色随时间改变
3、查询uniform定义的变量 ourColor的位置,glGetUniformLocation
4、设置uniform 值,glUniform4f
代码如下:
glUseProgram(shaderProgram);
GLfloat timeValue = glfwGetTime();//seconds
GLfloat greenValue = (sin(timeValue) / 2) + 0.5;
GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor")
;
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
注意:找到uniform位置不需要你useprogram,但修改uniform数据是需要useprogram。因为glUniform4f 它只设置当前在使用中的program。
还有,OpenGL的内核是C写的,没有C++的重载,可以看到,glUniform函数,有
•f: the function expects a float as its value
• i: the function expects an int as its value
• ui: the function expects an unsigned int as its value
• 3f: the function expects 3 floats as its value
• fv: the function expects a float vector/array as its value
这么多情形。
OK,程序运行结果就是,绿色会变色。