23.2漫反射光照模型


文档摘要

## 23.2 漫反射光照模型 在只有环境光下,模型看起来很假。 设计师设计的效果是这样的: 这是因为人眼是靠阴影,在大脑中创建3D物体的。 一个物体,如果所有的地方,颜色相同,那人类不会认为这是一个三维物体。 真实世界,是因为光子被上层反弹走了,没有击中更下层的地方,导致下层没有反射光子到人眼。 计算机没有那么大的算力去呈现真实光子物理现象。 前人就想出了一些简单的数学公式来简单模拟,这些数学公式,我们称之为光照模型。 法线 在学习光照模型之前,先来了解法线。 法线(normal line),是指始终垂直于某平面的直线。 那么我们平时说的顶点法线,这话看起来是错误的,因为法线是属于 。 在图形学里, 是一个实际存在的东西, 却是一个逻辑上的东西。

23.2 漫反射光照模型

CLion项目文件位于 samples\classic_lighting\diffuse

在只有环境光下,模型看起来很假。

设计师设计的效果是这样的:

这是因为人眼是靠阴影,在大脑中创建3D物体的。

一个物体,如果所有的地方,颜色相同,那人类不会认为这是一个三维物体。

真实世界,是因为光子被上层反弹走了,没有击中更下层的地方,导致下层没有反射光子到人眼。

计算机没有那么大的算力去呈现真实光子物理现象。

前人就想出了一些简单的数学公式来简单模拟,这些数学公式,我们称之为光照模型。

1. 法线

在学习光照模型之前,先来了解法线。

法线(normal line),是指始终垂直于某平面的直线。

那么我们平时说的顶点法线,这话看起来是错误的,因为法线是属于

在图形学里,是一个实际存在的东西, 却是一个逻辑上的东西。

一个模型要渲染出来,是先将顶点数据交由顶点处理器处理,组成了逻辑上的三角面。

即渲染的输入是顶点,而不是三角面。

那我要设置三角面的法线,就只能往顶点里塞数据,将法线数据作为顶点属性传入了。

这就是为什么我们平时叫顶点法线的原因。

1.1 顶点法线数据

Vertex 结构体中新增法线数据 normal_

//file:source\renderer\mesh_filter.h line:22 class MeshFilter:public Component{ public: MeshFilter(); ~MeshFilter(); public: //顶点 struct Vertex{ glm::vec3 position_; glm::vec4 color_; glm::vec2 uv_; glm::vec3 normal_; }; ......

法线数据上传后,从顶点着色器,传递到片段着色器。

//file:data\shader\diffuse_light.vert #version 330 core uniform mat4 u_model; uniform mat4 u_view; uniform mat4 u_projection; layout(location = 0) in vec3 a_pos; layout(location = 1) in vec4 a_color; layout(location = 2) in vec2 a_uv; layout(location = 3) in vec3 a_normal;//法线数据 out vec4 v_color; out vec2 v_uv; out vec3 v_normal; out vec3 v_frag_pos; void main() { gl_Position = u_projection * u_view * u_model * vec4(a_pos, 1.0); v_color = a_color; v_uv = a_uv; v_normal = a_normal;//传递给片段着色器。 v_frag_pos = vec3(u_model * vec4(a_pos, 1.0));//计算片段位置,就是顶点世界坐标。 }

然后在片段着色器,参与计算。

2. 漫反射光照模型

将从光源点 到 片段 的向量看作光的方向。

计算 光的方向 与 法线的角度Cos值,作为片段受光照影响的强弱。

当光源直射时,光方向 与 法线角度为0,Cos值为1,此时受光最强。

当片段位于背面或侧面,光方向 与 法线角度为 -1 或0,此时不受光。

这就是漫反射光照模型。

上述计算过程,在片段着色器中,代码如下:

//file:data/shader/diffuse_light.frag #version 330 core uniform sampler2D u_diffuse_texture;//颜色纹理 uniform vec3 u_ambient_light_color;//环境光 uniform float u_ambient_light_intensity;//环境光强度 uniform vec3 u_light_pos;//光源位置 uniform vec3 u_light_color;//光颜色 uniform float u_light_intensity;//光强度 in vec4 v_color;//顶点色 in vec2 v_uv; in vec3 v_normal; in vec3 v_frag_pos; layout(location = 0) out vec4 o_fragColor; void main() { //ambient vec3 ambient_color = u_ambient_light_color * u_ambient_light_intensity * texture(u_diffuse_texture,v_uv).rgb; //diffuse vec3 normal=normalize(v_normal);//法线 vec3 light_dir=normalize(u_light_pos - v_frag_pos);//灯光方向 float diffuse_intensity = max(dot(normal,light_dir),0.0);//计算cos角度值,作为受光强度。 vec3 diffuse_color = u_light_color * diffuse_intensity * u_light_intensity * texture(u_diffuse_texture,v_uv).rgb;//计算漫反射颜色 o_fragColor = vec4(ambient_color + diffuse_color,1.0);//最终输出颜色=环境光照颜色+漫反射光照颜色 }

首先是灯光的参数:光源位置、光颜色、光强度:

uniform vec3 u_light_pos;//光源位置 uniform vec3 u_light_color;//光颜色 uniform float u_light_intensity;//光强度

这几个数据在逻辑代码中上传:

--file:samples\classic_lighting\diffuse\example\login_scene.lua line:97 function LoginScene:Update() ...... --设置灯光位置、颜色、强度 self.material_:SetUniform3f("u_light_pos",glm.vec3(0,0,20)) self.material_:SetUniform3f("u_light_color",glm.vec3(1.0,1.0,1.0)) self.material_:SetUniform1f("u_light_intensity",1.0) ...... end

然后计算 光的方向 与 法线的角度Cos值,作为片段受光照影响的强弱。

//file:data/shader/diffuse_light.frag line:21 void main() { ...... //diffuse vec3 normal=normalize(v_normal);//法线 vec3 light_dir=normalize(u_light_pos - v_frag_pos);//灯光方向 float diffuse_intensity = max(dot(normal,light_dir),0.0);//计算cos角度值,作为受光强度。 vec3 diffuse_color = u_light_color * diffuse_intensity * u_light_intensity * texture(u_diffuse_texture,v_uv).rgb;//计算漫反射颜色 o_fragColor = vec4(ambient_color + diffuse_color,1.0);//最终输出颜色=环境光照颜色+漫反射光照颜色 }

将环境光照颜色与漫反射光照颜色叠加,作为最终输出颜色。

3. 测试


发布者: 作者: 转发
评论区 (0)
U