颜色
什么是颜色
颜色是通过眼、脑和我们的生活经验所产生的一种对光的视觉效应,我们肉眼所见到的光线,是由频率范围很窄的电磁波产生的,不同频率的电磁波表现为不同的颜色,对色彩的辨认是肉眼受到电磁波辐射能刺激后所引起的一种视觉神经的感觉。
其实在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色。
如何表示物体颜色
首先要知道,在实际模型中物体吸收了其中的大部分颜色,它仅反射了代表物体颜色的部分,被反射颜色的组合就是我们眼睛所感知到的颜色。
具体操作:
把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)
举个例子
光源——白光
物体——蓝色
物体反射颜色——蓝色
glm::vec3 lightColor(1.0f, 1.0f, 1.0f);//白色
glm::vec3 toyColor(0.0f, 1.0f, 0.0f);//蓝色
glm::vec3 result = lightColor * toyColor; // = (0.0f, 1.0f, 0.0f);//蓝色
再举个例子
光源——蓝光
物体——珊瑚红
物体反射颜色——深绿色
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);//深绿
光照场景的搭建
首先知道需要些什么
- 光源
- 物体
- VAO,VBO
这里建议的做法是将光源与物体的顶点着色器与片段着色器分开来设置,这样容易独自改变而不会受其他因素影响。
光源的顶点着色器:
#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;
void main()
{
FragColor = vec4(1.0); //这边光源颜色设置为白色
}
物体的顶点着色器:
#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);
}
VAO,VBO
可以让这个灯和其它物体使用同一个VAO,但考虑到接下来会频繁地对顶点数据和属性指针做出修改,我们并不想让这些修改影响到光源(我们只关心光源的顶点位置),因此我们有必要为光源与物体分别创建VAO,由于VBO只是为了储存数据,只需要绑定VBO不用再次设置VBO的数据,这边绘制的都是一样的正方体,VBO可以共用
物体 cubeVAO+VBO
unsigned int VBO, cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(cubeVAO);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
光源 lightCubeVAO+VBO
unsigned int lightCubeVAO;
glGenVertexArrays(1, &lightCubeVAO);
glBindVertexArray(lightCubeVAO);
// we only need to bind to the VBO (to link it with glVertexAttribPointer), no need to fill it; the VBO's data already contains all we need (it's already bound, but we do it again for educational purposes)
glBindBuffer(GL_ARRAY_BUFFER, VBO);//这个可以不要
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
设置渲染循环
//[...]
// render
// ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
lightingShader.use();
lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
//物体
// view/projection transformations
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
lightingShader.setMat4("projection", projection);
lightingShader.setMat4("view", view);
// world transformation
glm::mat4 model = glm::mat4(1.0f);
lightingShader.setMat4("model", model);
// render the cube
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
//光源
lightCubeShader.use();
lightCubeShader.setMat4("projection", projection);
lightCubeShader.setMat4("view", view);
model = glm::mat4(1.0f);
model = glm::translate(model, lightPos);//glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
model = glm::scale(model, glm::vec3(0.2f)); // 这边缩放以表示光源
lightCubeShader.setMat4("model", model);
glBindVertexArray(lightCubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
//[....]
实现情况:
灯光为白色, 物体为珊瑚红色。