着色器
着色器(Shader)是用于控制图形渲染流程的程序,主要分为顶点着色器和片段着色器。源代码提供着色器对象,然后通过着色器对象被编译为一个目标形式(obj文件),编译之后,着色器对象可以连接到一个程序对象。程序对象可以连接多个着色器对象
获得链接之后着色器对象一般过程包括6个步骤
- 创建一个顶点着色器对象和一个片段着色器对象
- 将源代码连接到每个着色器对象
- 编译着色器对象
- 创建一个程序对象
- 将编译后着色器对象连接到程序对象
- 链接程序对象
// 创建和编译着色器程序
//顶点着色器
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// 检查编译错误
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;
}
// 片段着色器
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// 检查编译错误
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//着色器程序
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
//链接错误检查
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glCreateShader 创建着色器
glDeleteShader 删除着色器句柄
glShaderSource 用着色器源代码
glCompileShader 需要编译着色器对象句柄
glCreateProgram 创建程序对象
glDeleteProgram 删除的程序对象的句柄
glAttachShader 连接着色器和程序
GLSL语言
可以通过这篇博客学习GLSL语法GLSL
下面是我随便找到几个GLSL学习案例
1、如何在三角形上使用顶点颜色和简单矩阵变化
// 顶点着色器
#version 330 core
layout(location = 0) in vec3 aPos; // 从应用程序传入的顶点位置属性
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); // 设置裁剪坐标
//把坐标放进数组里去
}
// 片段着色器
#version 330 core
out vec4 FragColor; // 输出颜色
void main()
{
FragColor = vec4(1.0, 0.5, 0.2, 1.0); // 设置片段颜色为橙色
}
#version 330 core指定了GLSL的版本,layout(location = 0) in vec3 aPos;定义了一个输入变量,表示顶点位置。
2、较为空间复杂的变化
// 顶点着色器
#version 330 core //版本
layout(location = 0) in vec3 aPos; // 顶点位置
layout(location = 1) in vec3 aColor; // 顶点颜色
out vec3 ourColor; // 传递颜色给片段着色器
uniform mat4 model; // 模型矩阵
uniform mat4 view; // 视图矩阵
uniform mat4 projection; // 投影矩阵
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
ourColor = aColor;
}
// 片段着色器
#version 330 core
in vec3 ourColor; // 从顶点着色器传递的颜色
out vec4 FragColor; // 输出颜色
void main()
{
FragColor = vec4(ourColor, 1.0); // 将顶点颜色传递给片段颜色
}
layout(location = 1) in vec3 aColor; 定义了一个输入变量表示顶点颜色。
**out vec3 ourColor; **将颜色从顶点着色器传递到片段着色器。
**uniform mat4 model;, uniform mat4 view;, uniform mat4 projection; **定义了三个uniform变量,表示模型矩阵、视图矩阵和投影矩阵。
**gl_Position = projection * view * model * vec4(aPos, 1.0); **在顶点着色器中进行了矩阵变换。
3、深度纹理的可视化。该程序的主要目的是将深度纹理映射到屏幕上,以便可视化深度信息。
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D depthMap;
uniform float near_plane;
uniform float far_plane;
//required when using a perspective projection matrix
float LinearizeDepth(float depth)
{
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane));
}
void main()
{
float depthValue = texture(depthMap, TexCoords).r; // 将深度值转换回裁剪空间坐标
//FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0); // perspective
FragColor = vec4(vec3(depthValue), 1.0); // orthographic
}
- out vec4 FragColor; 表示片段着色器的输出颜色。
- in vec2 TexCoords; 表示从顶点着色器传递过来的纹理坐标。
- uniform sampler2D depthMap; 是深度纹理的纹理单元。
- uniform float near_plane; 和 uniform float far_plane; 是近平面和远平面的值,它们在LinearizeDepth函数中用于线性化深度值。
这个函数用于将深度值从非线性空间转换为线性空间,以更好地在屏幕上显示深度信息。在此之后,FragColor 将深度值映射到颜色输出。在当前的注释中,它使用 vec3(depthValue) 将深度值映射到RGB颜色通道。