2018/7/29--OpenGL学习笔记(五)Light-Color/Basic Lighting

这篇博客详细介绍了OpenGL中的光照模型,包括环境光照、漫反射光照和镜面光照的原理及实现。通过实例展示了如何创建光照场景,计算漫反射光照和镜面光照,并解释了法向量、环境因子、光源位置等因素对光照的影响。文章末尾还分享了作者在学习过程中的一个小插曲,提醒读者注意不同章节的shader管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开篇的话:终于磨了几天,把光照部分看完了,中间还因为项目问题学习了git的使用,光照这部分的知识还是需要很仔细的理解原理的,最开始这几篇一定要好好理解,多看几遍,不然到后面,各种向量一多,都不知道这个点成那个得出来的是什么结果。

在学习光照这部分的时候,有一个大坑,我会在本片片尾阐述。


(介绍光的内容我就不多说了,初高中物理都学过,我们看到的颜色,是物体所反射的颜色,太阳光是七色光)

我们定义一个太阳光,一个受光物体,将这两个颜色向量作分量相乘:

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);//反射的颜色

物体的颜色吸收了白色光源中很大一部分的颜色,但它根据自身的颜色值对红、绿、蓝三个分量都做出了一定的反射。这也表现了现实中颜色的工作原理。

把光源改为绿色:

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);

可以看到,并没有红色和蓝色的光让我们的玩具来吸收或反射。这个玩具吸收了光线中一半的绿色值,但仍然也反射了一半的绿色值。物体现在看上去是深绿色(Dark-greenish)的。

创建一个光照场景

首先我们需要一个物体来作为被投光(Cast the light)的对象,我们将使用前面教程中的那个(贴着笑脸的)的立方体箱子。

使用之前教程顶点着色器的精简版:

#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);
}

我们还要创建一个表示灯(光源)的立方体,所以我们还要为这个灯创建一个专门的VAO。

unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
// 只需要绑定VBO不用再次设置VBO的数据,因为箱子的VBO数据中已经包含了正确的立方体顶点数据
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 设置灯立方体的顶点属性(对我们的灯来说仅仅只有位置数据)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

(这套东西都很简单了,创建VAO,绑定VBO,设置属性·····)

定义一个fragmentshader:(用于我们创建的受光的BOX)

#version 330 core
out vec4 FragColor;

uniform vec3 objectColor;
uniform vec3 lightColor;

void main()
{
    FragColor = vec4(lightColor * objectColor, 1.0);
}

在主程序中为fragmentshader中的两个uniform变量赋值:

// 在此之前不要忘记首先 use 对应的着色器程序(来设定uniform)
lightingShader.use();
lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("lightColor",  1.0f, 1.0f, 1.0f);

光源fragmentshader:(主程序中定义光源颜色,传入shader中即可)

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0); // 将向量的四个分量全部设置为1.0
}

我们创建的光源物体的vertexshader和受光物体的vertexshader一样。

在主程序中我们实例化我们的两个shader:

//受光物体
Shader lightingShader("shader/vertexShader.vs", "shader/fragmentShader.vs");
//光源物体
Shader lampShader("shader/lightvertexShader.vs", "shader/lightfragmentShader.vs");

(好吧,我承认这个名字特别容易搞混!我已经习惯了。)

明一个全局vec3变量来表示光源在场景的世界空间坐标中的位置:

glm::vec3 lightPos(1.2f, 1.0f, 2.0f);

像摄像机一样,定义好我们的三个矩阵:(model,view,projection)

glm::mat4 model, view, projection;
view = camera.GetViewMatrix();
projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);

设置光源的位置,并缩放它:

model = glm::mat4();
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f));

绘制两个不同的立方体:(整合以上代码)

glm::mat4 model, view, projection;
view = camera.GetViewMatrix();
projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);

//受光cube渲染
lightingShader.use();
lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
lightingShader.setMat4("model", model);

lightingShader.setMat4("view", view);
lightingShader.setMat4("projection", projection);

glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);


//光源白色cube渲染
lampShader.use();
model = glm::mat4();
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f));

lampShader.setMat4("model", model);
lampShader.setMat4("view", view);
lampShader.setMat4("projection", projection);

glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);

OK!出图:

第一小节还是十分简单的,贴出我的源码:(shader的源码,上面都给出过,就不贴了)

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "Shader.h"
#include "camera.h"

#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow*window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;

float deltaTime = 0.0f;
float lastFrame = 0.0f
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值