CPU端设置着色器

着色器程序在OpenGL中是以C风格的字符串保存的,在使用前需要进行动态编译。

创建着色器

1
2
3
unsigned int shader;
shader = glCreateShader(type);
// type = GL_VERTEX_SHADER 或 GL_FRAGMENT_SHADER

编译着色器代码

1
2
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
  • glShaderSource
    第一个参数要编译的着色器对象。
    第二参数指定了传递的源码字符串数量,这里只有一个。
    第三个参数是顶点着色器真正的源码。
    第四个参数指定字符串长度的数组。

  • glCompileShader
    编译着色器代码。

  • 像素着色器等处理相同

连接着色器代码

我们需要将不同的Shader代码连接成一个ShaderProgram才能使用。

1
2
3
4
5
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

使用着色器

1
glUseProgram(shaderProgram);

删除着色器

1
2
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

着色器代码查错

1
2
3
4
5
6
7
8
int  success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}

GPU端的着色器程序

OpenGL的着色器语言称为GLSL

GLSL

数据类型

  • GLSL基础数据类型有int、float、double、uint、bool等常见的基础数据类型
  • 也有许多向量类型,如:
    n=1、2、3、4
    |类型 |含义 |
    |-------|---------------------------|
    |vecn |包含n个float分量的默认向量 |
    |bvecn |包含n个bool分量的向量 |
    |ivecn |包含n个int分量的向量 |
    |uvecn |包含n个unsigned int分量的向量|
    |dvecn |包含n个double分量的向量 |

输入输出

数据输入

  • 使用in关键字,接收上一阶段的shader传递来的数据
  • 使用**layout(location = <C++代码中的属性位置>)**连接输入的属性。

数据输出

  • 使用out关键字,定义着色器输出的变量,可以用于输出渲染结果也可以向下一阶段shader传递数据。

要求:in和out的变量名称和变量类型完全相同

例:

1
2
3
4
5
6
7
8
9
10
11
12
//Vertex Shader
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1

out vec3 ourColor; // 向片段着色器输出一个颜色

void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}
1
2
3
4
5
6
7
8
9
10
11
//Fragment Shader
#version 330 core

in vec3 ourColor; //接收VS中out的属性(要求同类型、同名称)

out vec4 FragColor; //FS必须输出的颜色

void main()
{
FragColor = vec4(ourColor, 1.0);
}

uniform关键字

使用uniform

uniform关键字是CPU向GPU传输数据的另一种途径。
其,

  • 将变量声明为全局的,所有着色器程序均可访问,因此不能重名。可以在任意阶段访问、修改。
  • 会持续存在。会保存某一值,直到再次修改。
在C++代码中设置uniform变量值

着色器代码:

1
2
3
4
5
6
7
8
9
#version 330 core
out vec4 FragColor;

uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量

void main()
{
FragColor = ourColor;
}

在C++代码中进行更改。

1
2
3
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

注意:更新一个uniform之前必须先使用程序(调用glUseProgram)

Shader类

可以找些参考,对Shader进行一个封装方便使用。