1 - 颜色
本节将会深入讨论什么是颜色,并为以后的光照部分创建一个场景。
颜色
颜色由RGB三个分量组成,例如要想创建一个珊瑚红色(Coral),只需定义颜色向量如下:
glm::vec3 coral(1.0f, 0.5f, 0.31f);
实际上,我们在现实生活中看到某一物体的颜色并不是它所真正拥有的,而是它所 反射(Reflected)的颜色。如下图,将白光照到珊瑚红色的表面上,只有部分红色被反射:
光源和物体表面颜色综合的过程如下:
glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 objColor(1.0f, 0.5f, 0.31f);
// 结果
glm::vec3 result = lightColor * objColor;
可以使用不同的光源颜色来让物体显现出意想不到的颜色。有创意地利用颜色其实并不难。
创建光照场景
我们需要创建一个可见的光源和一个被光投射(Cast)的物体,用于测试模拟光照的效果。
创建测试物体
我们使用一个立方体来代表被投射的物体,为方便,顶点数据还是用之前的。
// 定义顶点和索引信息
float vertices[] = {
-0.5f, -0.5f, -0.5f, // 0
0.5f, -0.5f, -0.5f, // 1
0.5f, 0.5f, -0.5f, // 2
-0.5f, 0.5f, -0.5f, // 3
-0.5f, -0.5f, 0.5f, // 4
0.5f, -0.5f, 0.5f, // 5
0.5f, 0.5f, 0.5f, // 6
-0.5f, 0.5f, 0.5f // 7
};
unsigned int indices[] = {
// 注意索引从0开始!
0,1,2,2,3,0,
4,5,6,6,7,4,
7,3,0,0,4,7,
6,2,1,1,5,6,
0,1,5,5,4,0,
3,2,6,6,7,3
};
然后为该物体绑定VAO,VBO,EBO,解析顶点信息:
// ---------------被测试物体-------------------
// 绑定VAO
glBindVertexArray(cubeVAO);
// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 绑定EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 解析顶点位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 解绑VAO
glBindVertexArray(0);
// -------------------------------------------
创建可见光源
为图省事,光源也用立方体来绘制:
// ---------------光源------------------------
// 绑定VAO
glBindVertexArray(lightVAO);
// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 绑定EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 解析顶点位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 解绑VAO
glBindVertexArray(0);
// -------------------------------------------
然后声明光源的位置:
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
配置着色器
接下来配置顶点着色器来绘制立方体,这次没有纹理坐标了,因此写的简单点:
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
然后是立方体片段着色器:
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
void main()
{
FragColor = vec4(lightColor * objectColor, 1.0);
}
需要注意的是,光源得一直是白色,因此它得有自己的片段着色器:
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0); // 将向量的四个分量全部设置为1.0
}
绘制物体
配置好MVP矩阵后(M直接用初始值),首先是绘制物体:
cubeShader.use();
cubeShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
cubeShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
cubeShader.setMat4("model", model);
cubeShader.setMat4("view", view);
cubeShader.setMat4("projection", proj);
glBindVertexArray(cubeVAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
然后是绘制光源:
lightShader.use();
// 这里将光源缩放平移一下
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f));
lightShader.setMat4("model", model);
lightShader.setMat4("view", view);
lightShader.setMat4("projection", proj);
glBindVertexArray(lightVAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
最终绘制的效果如下:
参考资料
- 颜色 - LearnOpenGL CN (learnopengl-cn.github.io)