第2课_模型增加直线光源
热度🔥:13 免费课程
授课语音
为模型增加直线光源
在 3D 渲染中,光源是决定物体如何与光线交互并最终呈现到屏幕上的关键。为了使场景中的模型具有更自然的光照效果,我们可以向渲染系统中添加不同类型的光源,比如点光源、方向光源和直线光源等。
在这里,我们将介绍如何为模型添加 直线光源,并结合 GLSL 来实现这一效果。
1. 直线光源的概念
直线光源通常是指一种具有方向的光源,其光线沿一个方向发射,但没有明确的起始位置。在计算机图形学中,通常称之为 方向光源(Directional Light)。
- 方向光源:这种光源没有位置,它仅有一个方向。例如,太阳的光线可以看作是方向光源,因为它照射到地面时,光线的方向基本上是固定的。
直线光源的主要特征是:
- 它的光线沿着某个固定的方向传播。
- 所有照射到物体上的光线都具有相同的方向,并且光强度通常是均匀的。
2. 直线光源的数学模型
为了在渲染中添加直线光源,我们需要设置一个光源的 方向向量。在 GLSL 着色器中,这个方向向量将影响每个片段的光照计算。
一般来说,光源对物体的照明效果与物体表面法线的夹角以及视角有关。我们常用 漫反射(Diffuse Reflection)模型来模拟直线光源的效果。漫反射强度和光源方向与法线的夹角有关系,越接近正面,反射越强。
3. 直线光源的 GLSL 实现
3.1 顶点着色器修改
在顶点着色器中,我们需要处理物体顶点的变换以及传递必要的信息(如法线向量、光源方向等)到片段着色器。假设我们的直线光源方向是 (lightDir)
。
顶点着色器代码如下:
#version 330 core
layout(location = 0) in vec3 position; // 顶点位置
layout(location = 1) in vec3 normal; // 顶点法线
out vec3 fragNormal; // 传递给片段着色器的法线
out vec3 fragPosition; // 传递给片段着色器的顶点位置
uniform mat4 model; // 模型矩阵
uniform mat4 view; // 视图矩阵
uniform mat4 projection; // 投影矩阵
void main() {
fragPosition = vec3(model * vec4(position, 1.0)); // 变换后的顶点位置
fragNormal = normalize(mat3(transpose(inverse(model))) * normal); // 变换后的法线
gl_Position = projection * view * vec4(fragPosition, 1.0); // 顶点变换后的坐标
}
在这个顶点着色器中:
fragNormal
是变换后的法线,会传递给片段着色器。fragPosition
是变换后的顶点位置,用于计算与光源的相对位置。
3.2 片段着色器修改
片段着色器中,我们将计算每个片段的颜色,包括光照和材质的影响。为了计算光照,我们使用 漫反射 反射模型。
片段着色器代码如下:
#version 330 core
in vec3 fragNormal; // 从顶点着色器传来的法线
in vec3 fragPosition; // 从顶点着色器传来的顶点位置
out vec4 finalColor; // 输出的颜色
uniform vec3 lightDir; // 直线光源的方向
uniform vec3 lightColor; // 光源的颜色
uniform vec3 objectColor; // 物体的颜色
void main() {
// 计算法线和光源方向的点积
float diff = max(dot(normalize(fragNormal), normalize(lightDir)), 0.0);
// 计算最终颜色
vec3 diffuse = diff * lightColor * objectColor;
finalColor = vec4(diffuse, 1.0); // 设置最终颜色,alpha值为1
}
在这个片段着色器中:
lightDir
是从外部传入的直线光源的方向向量。fragNormal
是传递过来的顶点法线。lightColor
和objectColor
分别是光源的颜色和物体的颜色。- 通过
dot()
函数计算法线和光源方向的夹角(即漫反射光照强度),并乘以光源的颜色和物体的颜色,得到最终的像素颜色。
3.3 在 OpenGL 中传递光源参数
在 OpenGL 的主程序中,我们需要传递光源的方向和其他必要的参数给着色器。
// 设置光源的方向
glm::vec3 lightDir = glm::normalize(glm::vec3(-1.0f, -1.0f, -1.0f)); // 假设光源的方向是 (-1, -1, -1)
// 设置光源的颜色
glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f); // 白色光
// 设置物体的颜色
glm::vec3 objectColor = glm::vec3(1.0f, 0.0f, 0.0f); // 红色物体
// 向着色器传递光源方向
glUseProgram(shaderProgram);
glUniform3fv(glGetUniformLocation(shaderProgram, "lightDir"), 1, glm::value_ptr(lightDir));
glUniform3fv(glGetUniformLocation(shaderProgram, "lightColor"), 1, glm::value_ptr(lightColor));
glUniform3fv(glGetUniformLocation(shaderProgram, "objectColor"), 1, glm::value_ptr(objectColor));
在这段代码中,我们设置了光源的方向为 (-1, -1, -1)
,光源的颜色为白色,并且物体的颜色为红色。
4. 小结
通过在 GLSL 中实现直线光源,我们可以为渲染的 3D 场景添加方向光源效果。具体步骤包括:
- 在顶点着色器中传递顶点的位置和法线数据。
- 在片段着色器中计算光照效果,使用点积计算漫反射强度。
- 在 OpenGL 程序中设置光源的参数并传递给着色器。
通过这种方式,我们能够实现更真实的光照效果,使得 3D 渲染更加生动和自然。