图形学实验三第二部分——GLSL实现的三种光照模型。 此次试验用GLSL(OpenGL
Shading
Language)着色语言实现OpenGL自带的光照模型,比较不同的着色方法带来的不同。
点的着色过程
首先,对某个点的计算光照的方法如下:
环境光(Ambient)与漫反射(Diffuse)
即环境光直接是环境光,漫反射经过反射(由于是单位向量直接取内积)后反射到所有方向。
其中kk是衰减因子,在实验中忽略了。
1 2 3 4 5 6 7 8 9
| float ambientStrength = 0.1f; vec3 ambient = ambientStrength * lightColor;
vec3 norm = normalize(Normal); vec3 lightDir = normalize(lightPos - FragPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * lightColor;
|
镜面反射
如图,镜面反射需要先计算反射光的方向,再乘以与视线向量的夹角的余弦值,其中余弦值以高光系数nshinynshiny作幂次。 反射光RR的方向可以由下图求得
也可以直接在GLSL中调用relect()函数,该函数接收入射光方向和法向量,返回反射后的光线方向:
1 2 3 4 5 6
| float specularStrength = 0.5f; vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular = specularStrength * spec * lightColor;
|
Gouraud着色
Gouraud着色为只对三角面片的顶点计算着色,其他的点通过插值计算颜色,GLSL中的顶点和片段着色器分别如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal;
out vec3 LightingColor;
uniform vec3 lightPos; uniform vec3 viewPos; uniform vec3 lightColor;
uniform mat4 model; uniform mat4 view; uniform mat4 projection;
void main() { gl_Position = projection * view * model * vec4(position, 1.0); vec3 Position = vec3(model * vec4(position, 1.0)); vec3 Normal = mat3(transpose(inverse(model))) * normal; float ambientStrength = 0.1; vec3 ambient = ambientStrength * lightColor; vec3 norm = normalize(Normal); vec3 lightDir = normalize(lightPos - Position); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * lightColor; float specularStrength = 1.0; vec3 viewDir = normalize(viewPos - Position); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular = specularStrength * spec * lightColor;
LightingColor = ambient + diffuse + specular; }
|
顶点着色器计算之后传入片段着色器后会自动对顶点着色器的输出进行插值。
1 2 3 4 5 6 7 8 9 10 11 12 13
| #version 330 core out vec4 FragColor;
in vec3 LightingColor;
uniform vec3 objectColor;
void main() { FragColor = vec4(LightingColor * objectColor, 1.0); }
|
结果演示如下,可以看出明显的区域和插值结果:
0.5
0.75
Normal
1.25
1.5
2
[x]
Player version
Player FPS
Video type
Video url
Video resolution
Video duration
Video load failed
Phong着色
和Gouraud着色不同,Phong着色则是对法向量进行插值,之后对每个点计算光照,因此,光照的计算是在片段着色器中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal;
out vec3 Normal; out vec3 FragPos;
uniform mat4 model; uniform mat4 view; uniform mat4 projection;
void main() { gl_Position = projection * view * model * vec4(position, 1.0f); FragPos = vec3(model * vec4(position, 1.0f)); Normal = mat3(transpose(inverse(model))) * normal; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #version 330 core out vec4 color;
in vec3 FragPos; in vec3 Normal; uniform vec3 lightPos; uniform vec3 viewPos; uniform vec3 lightColor; uniform vec3 objectColor;
void main() { float ambientStrength = 0.1f; vec3 ambient = ambientStrength * lightColor; vec3 norm = normalize(Normal); vec3 lightDir = normalize(lightPos - FragPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * lightColor; float specularStrength = 0.5f; vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular = specularStrength * spec * lightColor; vec3 result = (ambient + diffuse + specular) * objectColor; color = vec4(result, 1.0f); }
|
结果是最好的:
0.5
0.75
Normal
1.25
1.5
2
[x]
Player version
Player FPS
Video type
Video url
Video resolution
Video duration
Video load failed
Flat着色
Flat就比较Naive了,每一个三角面片只计算一个光照,并将这个光照当做这个三角面片的光照:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
#version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal;
flat out vec3 LightingColor;
uniform vec3 lightPos; uniform vec3 viewPos; uniform vec3 lightColor;
uniform mat4 model; uniform mat4 view; uniform mat4 projection;
void main() { gl_Position = projection * view * model * vec4(position, 1.0); vec3 Position = vec3(model * vec4(position, 1.0)); vec3 Normal = mat3(transpose(inverse(model))) * normal; float ambientStrength = 0.1; vec3 ambient = ambientStrength * lightColor; vec3 norm = normalize(Normal); vec3 lightDir = normalize(lightPos - Position); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * lightColor; float specularStrength = 1.0; vec3 viewDir = normalize(viewPos - Position); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular = specularStrength * spec * lightColor;
LightingColor = ambient + diffuse + specular; }
|
1 2 3 4 5 6 7 8
| #version 330 core flat in vec3 LightingColor; layout( location = 0 ) out vec4 FragColor; uniform vec3 objectColor; void main() { FragColor = vec4(LightingColor * objectColor, 1.0); }
|
结果有明显的马赫带(x
0.5
0.75
Normal
1.25
1.5
2
[x]
Player version
Player FPS
Video type
Video url
Video resolution
Video duration
Video load failed
三种着色方法比较
0.5
0.75
Normal
1.25
1.5
2
[x]
Player version
Player FPS
Video type
Video url
Video resolution
Video duration
Video load failed