[Shading]ADS光照模型实例(OpenGL实现)
keywords: [Shading]ADS光照模型实例(OpenGL实现)
keywords:ambient diffuse specular、Phong Shading、Phong reflection model
公式概述
ADS光照模型又称为“冯氏反射模型”(Phong reflection model),为什么叫冯氏:
裴祥风(Bùi Tường Phong音译, 1942年—1975年),美国电脑CG研究学者,于越南出生。他于1973年在尤他大学取得哲学博士学位,并发明了Phong反射模型及Phong著色法,并广为CG界采用。1975死于白血病。
ADS光照模型公式缩写:
LightIntensity = Ambient + Diffuse + Specular;
参数说明:
- Ambient 环境光
- Diffuse 漫反射
- Specular 全反射光 / 镜面光
三个参数渲染效果示例:
三个参数拆解如下:
Ambient = La * Ka;
Diffuse = Ld * Kd * max( dot(s, n), 0.0 );
Specular = Ls * Ks * pow( max( dot(r, v), 0.0 ), f );
参数说明:
- La 环境光强度(Ambient light intensity)
- Ka 材质环境光反射率 / 材质环境光反射系数(Ambient reflectivity)
- Ld 漫射光强度 / 散射光强度(Diffuse light intensity)
- Kd 材质漫反射率 / 材质漫反射系数(Diffuse reflectivity)
- s 顶点 / 曲面点 到光源方向的单位向量(Direction from the surface point to the light source)
- n 顶点 / 曲面点 的法线单位向量(Normal vector at the surface point)
- Ls 镜面光强度 / 全反射光强度(Specular light intensity)
- Ks 材质镜面反射率 / 材质镜面反射系数(Specular reflectivity)
- r 完全反射向量( the vector of perfect reflection)
- v 顶点 / 曲面点 到摄像机方向的向量( the vector towards the viewer)
- f 镜面高光(specular highlights),值范围在1到200之间,值越小,镜面亮点越大
光源出射强度 / 出射光强度(Intensity of the outgoing light ) I
的完整计算公式如下:
$$ I = La \cdot Ka+Ld \cdot Kd \cdot \left(\vec{s} \cdot \vec{n}\right)+Ls \cdot Ks \cdot \left(\vec{r} \cdot \vec{v}\right)^f $$
渲染实例
OpenGL API 版本为4.1。
假设不考虑环境光和镜面光,只考虑漫射光,渲染效果:
shader 代码:
diffuse.vert
#version 410
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
out vec3 LightIntensity;
uniform vec4 LightPosition; // Light position in eye coords.
uniform vec3 Kd; // Diffuse reflectivity
uniform vec3 Ld; // Diffuse light intensity
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;
void main()
{
vec3 tnorm = normalize( NormalMatrix * VertexNormal);
vec4 eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);
vec3 s = normalize(vec3(LightPosition - eyeCoords));
LightIntensity = Ld * Kd * max( dot( s, tnorm ), 0.0 );
gl_Position = MVP * vec4(VertexPosition,1.0);
}
diffuse.frag
#version 410
in vec3 LightIntensity;
layout( location = 0 ) out vec4 FragColor;
void main() {
FragColor = vec4(LightIntensity, 1.0);
}
同时计算环境光、漫反射、镜面反射的渲染效果:
shader 代码:
phong.vert
#version 410
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
out vec3 LightIntensity;
struct LightInfo {
vec4 Position; // Light position in eye coords.
vec3 La; // Ambient light intensity
vec3 Ld; // Diffuse light intensity
vec3 Ls; // Specular light intensity
};
uniform LightInfo Light;
struct MaterialInfo {
vec3 Ka; // Ambient reflectivity
vec3 Kd; // Diffuse reflectivity
vec3 Ks; // Specular reflectivity
float Shininess; // Specular shininess factor
};
uniform MaterialInfo Material;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;
void main()
{
vec3 tnorm = normalize( NormalMatrix * VertexNormal);
vec4 eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);
vec3 s = normalize(vec3(Light.Position - eyeCoords));
vec3 v = normalize(-eyeCoords.xyz);
vec3 r = reflect( -s, tnorm );
float sDotN = max( dot(s,tnorm), 0.0 );
vec3 ambient = Light.La * Material.Ka;
vec3 diffuse = Light.Ld * Material.Kd * sDotN;
vec3 spec = vec3(0.0);
if( sDotN > 0.0 )
spec = Light.Ls * Material.Ks *
pow( max( dot(r,v), 0.0 ), Material.Shininess );
LightIntensity = ambient + diffuse + spec;
gl_Position = MVP * vec4(VertexPosition,1.0);
}
phong.frag
#version 410
in vec3 LightIntensity;
layout( location = 0 ) out vec4 FragColor;
void main() {
FragColor = vec4(LightIntensity, 1.0);
}
demo完整代码:ADS Reflection - github
参考书籍:
OpenGL 4.0 Shading Language Cookbook
在各种事物的常理中,爱情是无法改变和阻挡的,因为就本性而言,爱只会自行消亡,任何计谋都难以使它逆转。---意大利·薄伽丘《十日谈》