前言:该系列教程主要参考自网站www.opengl-tutorial.org和learnopengl.com/,基于开源GUI框架imgui v1.61实现,imgui自带的例子里面直接集成了glfw+gl3w环境,本系列教程将gl3w换成了glew,glew具体环境配置可参考:OpenGL环境配置教程:VS2012 + GLEW + GLFW + GLM。
教程目录(持续更新中):
现代OpenGL教程(一):绘制三角形(ImGui+OpenGL3.3)
现代OpenGL教程(二):矩阵变换(ImGui+OpenGL3.3)
现代OpenGL教程(三):绘制彩色立方体(ImGui+OpenGL3.3)
现代OpenGL教程(四):立方体纹理贴图(ImGui+OpenGL3.3)
现代OpenGL教程(五):obj模型加载(ImGui+OpenGL3.3)
现代OpenGL教程(六):鼠标和键盘(ImGui+OpenGL3.3)
现代OpenGL教程(七):基础光照——颜色(ImGui+OpenGL3.3)
现代OpenGL教程(八):基础光照——Phong光照模型(ImGui+OpenGL3.3)
现代OpenGL教程(九):基础光照——材质(ImGui+OpenGL3.3)
本节教程在上一节(现代OpenGL教程(六):鼠标和键盘(imgui+OpenGL3.3))的基础上,增加了调色板控制物体颜色的功能。本例完整代码下载地址:https://github.com/maijiaquan/blog-code/tree/master/opengl-color
运行效果
![](https://i-blog.csdnimg.cn/blog_migrate/5debd946bbe412117fb5b86e9d455c2a.gif)
本节概要
本节将会创建两个立方体,小立方体表示光源,大立方体表示受光照的物体。大立方体的颜色会根据其本身的颜色和光照的颜色而改变。由于我们不希望光源因为环境而变化,光源的片段着色器被定义了一个不变的白色常亮。
颜色值相乘的意义
假设我们用白光灯照射红苹果,我们会看到苹果呈现红色。并不是因为苹果会发红光(黑夜中苹果不会发光),而是因为苹果把红色光以外的光吸收了,而不被吸收的红色光被反射到了我们眼中。因此,我们感知到的非自发光物体的颜色,绝大部分都是反射颜色的组合。
在图形学领域,我们可以对上述现象做以下模拟:把光源的颜色与物体的颜色值相乘,得到的就是这个物体所反射的颜色。
例如:光源为绿色,照射到一个珊瑚色的玩具上面。
glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (0.0f, 0.5f, 0.0f);
由于并没有红色和蓝色的光让我们的玩具来吸收或反射,这个玩具吸收了光线中一半的绿色值,但仍然也反射了一半的绿色值。玩具现在看上去是深绿色的。
第一步:设置具有反射功能的立方体
1.立方体的顶点着色器
#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);
}
2.立方体的片段着色器
该着色器实现了光源的颜色和物体(反射的)颜色相乘。
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
void main()
{
FragColor = vec4(lightColor * objectColor, 1.0);
}
3.使用imgui创建调色板
ImVec4 cubeColor = ImVec4(1.0f, 0.5f, 0.31f, 1.00f);
ImVec4 lightColor = ImVec4(1.0f, 1.0f, 1.0f, 1.00f);
...
ImGui::ColorEdit3("cube color", (float*)&cubeColor);
ImGui::ColorEdit3("light color", (float*)&lightColor);
4.OpenGL中创建该立方体
GLuint cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glBindVertexArray(cubeVAO);
...
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
...
glUseProgram(cubeProgramID);
setVec3(cubeProgramID, "objectColor", cubeColor.x, cubeColor.y, cubeColor.z);
setVec3(cubeProgramID, "lightColor", lightColor.x, lightColor.y, lightColor.z);
setMat4(cubeProgramID, "projection", Projection);
setMat4(cubeProgramID, "view", View);
setMat4(cubeProgramID, "model", Model);
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
第二步:设置光源
1.光源的顶点着色器
#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);
}
2.光源的片段着色器
该片段着色器给光源定义了一个不变的常量白色,保证了光源的颜色一直是亮的。
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0); // set alle 4 vector values to 1.0
}
3.在OpenGL中创建该光源
为光源创建一个新的VAO,并设置光源立方体的顶点属性。
GLuint lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
位移光源,并缩小一点,以便跟大立方体区分开。
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
model = glm::mat4();
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f));
最后绘制该光源。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
本例完整代码下载地址:https://github.com/maijiaquan/blog-code/tree/master/opengl-color
参考资料:颜色 - LearnOpenGL CN