1、为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量,它在幕后是vec4
类型的。在main函数的最后,我们将gl_Position设置的值会成为该顶点着色器的输出。由于我们的输入是一个3分量的向量,我们必须把它转换为4分量的。
2、片段着色器,它需要一个vec4
颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果你在片段着色器没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)
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.0f, 0.5f, 0.2f, 1.0f);
}
2、顶点坐标有位置、颜色
float vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
#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设置为我们从顶点数据那里得到的输入颜色
}
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);
4、顶点坐标有纹理、颜色、位置
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main()
{
FragColor = texture(ourTexture, TexCoord);
}
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
#version 330 core
...
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
1、最终输出颜色现在是两个纹理的结合。GLSL内建的mix函数需要接受两个值作为参数,并对它们根据第三个参数进行线性插值。如果第三个值是0.0,它会返回第一个输入;如果是1.0,会返回第二个输入值。0.2会返回80%的第一个输入颜色和20%的第二个输入颜色,即返回两个纹理的混合色。
2、我们还可以把得到的纹理颜色与顶点颜色混合,来获得更有趣的效果。我们只需把纹理颜色与顶点颜色在片段着色器中相乘来混合二者的颜色:
FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
最终的效果应该是顶点颜色和纹理颜色的混合色:
3、我们使用GLSL内建的texture函数来采样纹理的颜色,它第一个参数是纹理采样器,第二个参数是对应的纹理坐标。texture函数会使用之前设置的纹理参数对相应的颜色值进行采样。这个片段着色器的输出就是纹理的(插值)纹理坐标上的(过滤后的)颜色。
4、当涉及变换(模型矩阵)
我们将修改顶点着色器让其接收一个mat4的uniform变量,然后再用矩阵uniform乘以位置向量:
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
// linearly interpolate between both textures (80% container, 20% awesomeface)
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0);
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
5、当含有摄像机
1、core.vs
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
out vec3 Color;
//uniform mat4 transform;
uniform mat4 model; //模型变化
uniform mat4 view; //相机坐标系
uniform mat4 projection; //投影变换
void main(){
//gl_Position = transform * vec4(position, 1.0f);
//从右向左乘:先乘 model,最后乘 projection
gl_Position = projection * view * model * vec4(position, 1.0f);
Color = color;
}
2、core.frag
#version 330 core
in vec3 Color;
out vec4 color;
void main(){
color = vec4(Color, 1.0f);
}
6、当有灯光(光模型)、摄像机
core1.vs
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
//out vec3 Color;
out vec3 Normal; //法向量
out vec3 FragPos; //每一个点的位置
//uniform mat4 transform;
uniform mat4 model; //模型变化,传入参数
uniform mat4 view; //相机坐标系
uniform mat4 projection; //投影变换
void main() {
//gl_Position = transform * vec4(position, 1.0f);
gl_Position = projection * view * model * vec4(position, 1.0f); //先乘 model,最后乘 projection
//Color = color;
FragPos = vec3(model * vec4(position, 1.0f));
Normal = mat3(transpose(inverse(model))) * normal; //平移不影响法向量,所以只要 3 * 3
}
core1.frag
#version 330 core
//in vec3 Color;
out vec4 color;
in vec3 FragPos;
in vec3 Normal;
uniform vec3 lightPos; //光源位置
uniform vec3 viewPos; //
uniform vec3 objectColor; //物体颜色
uniform vec3 lightColor; //光颜色
void main() {
//color = vec4(Color, 1.0f);
// ambient 环境部分
float ambientStrength = 0.1f;
vec3 ambient = ambientStrength * lightColor;
// diffuse 漫反射
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos); //光照方向,从光源位置到物体位置
float diff = max(dot(norm, lightDir), 0.0f); //光照和法向量点乘,与 0 取较大值
float diffuseStrength = 0.4f;
//vec3 diffuse = diffuseStrength * diff * lightColor;
vec3 diffuse = diffuseStrength * lightColor * diff;
// specular 镜面反射
float specularStrength = 2.5f;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 halfAngle = normalize(viewDir + lightDir); //半角
float spec = pow(max(dot(norm, halfAngle), 0.0f), 32);
vec3 specular = specularStrength * spec * lightColor;
// 三部分叠加
vec3 result = (ambient + diffuse + specular) * objectColor; //全加一起
color = vec4(result, 1.0f);
}
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 model; //模型变化,传入参数
uniform mat4 view; //相机坐标系
uniform mat4 projection; //投影变换
void main() {
gl_Position = projection * view * model * vec4(position, 1.0f); //先乘 model,最后乘 projection
}
light.frag
#version 330 core
uniform vec3 lightColor; //光颜色
out vec4 color;
void main() {
color = vec4(lightColor, 1.0f);
}
当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)
现在我们已经创建了表示灯和被照物体箱子,我们只需要再定义一个片段着色器就行了
7、asssimp导入模型,模型的着色器
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
TexCoords = texCoords;
}
#version 330 core
out vec4 color;
in vec2 TexCoords;
uniform sampler2D texture_diffuse1;
void main()
{
color = vec4(texture(texture_diffuse1, TexCoords));
}
8、加入天空盒
天空盒着色器:
要渲染天空盒的话,我们需要一组新的着色器,它们都不是很复杂。因为我们只有一个顶点属性,顶点着色器非常简单:
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main()
{
TexCoords = aPos;
gl_Position = projection * view * vec4(aPos, 1.0);
}
注意,顶点着色器中很有意思的部分是,我们将输入的位置向量作为输出给片段着色器的纹理坐标。片段着色器会将它作为输入来采样samplerCube
:
#version 330 core
out vec4 FragColor;
in vec3 TexCoords;
uniform samplerCube skybox;
void main()
{
FragColor = texture(skybox, TexCoords);
}
天空盒中物体的着色器
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoords);
}
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
天空盒中的物体,物体具有映射环境的效果
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
out vec3 Normal;
out vec3 Position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
Normal = mat3(transpose(inverse(model))) * normal;
Position = vec3(model * vec4(position, 1.0f));
}
#version 330 core
in vec3 Normal;
in vec3 Position;
out vec4 color;
uniform vec3 cameraPos;
uniform samplerCube skybox;
void main()
{
float ratio = 1.00 / 1.52;
vec3 I = normalize(Position - cameraPos);
vec3 R = refract(I, normalize(Normal), ratio);
color = texture(skybox, R);
}