1. 流程
光打在一个物体上,它反射出来的光是什么颜色的?
比如白色的太阳光,打在红色的物体上,我们看到的就是红色,而又因为白色光是所有可见颜色的集合,我们可不可以这样想:
白光打在物体上面,物体选择性接收rgb通道的光,反射出来的就是没有吸收的,比如下面这个例子,物体的颜色可以看作RGB反射率,白光与物体颜色相乘,结果就是反射出来的光
glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);
再比如绿光打到物体上,反射出来的也就是G通道的光
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);
有了这个假设,我们就可以搭建一个简单的光照场景:
一个白光灯立方体和数个珊瑚红的立方体
那么对于普通物体,它的片段着色器就应该是这样:
#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
}
同样的为了区别于其他物体,我们也给灯光绑定一个自己的VAO:
unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);//都是立方体,VBO可以通用,不用再设
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
然后在全局定义灯光的位置:
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));
接下来就分别渲染物体和灯光:
ourShader.use();
glBindVertexArray(VAO); // 一般每次使用时再绑定,这里只有一个VAO,所以实际上可以不绑
for (unsigned int i = 0; i < 10; i++)
{
model = view = projection = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
model = glm::translate(model, cubePositions[i]);
model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));
ourShader.setMat4("model",model);
ourShader.setMat4("view",view);
ourShader.setMat4("projection",projection);
ourShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
ourShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
lightShader.use();
model = glm::mat4(1.0f);
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f));
lightShader.setMat4("model", model);
lightShader.setMat4("view", view);
lightShader.setMat4("projection", projection);
glBindVertexArray(lightVAO);
效果: