Gouraud
Gouraud Shading (高洛德着色/高氏着色)是一种平滑着色方式,常用于三维软件,如Cinema4D,来源于法国计算机科学家Henri Gouraud(亨利·高洛德),它有一套复杂的光影数学计算。
这种着色的效果要好得多,也是在游戏中使用最广泛的一种着色方式。它可对3D模型各顶点的颜色进行平滑、融合处理,将每个多边形上的每个点赋以一组色调值,同时将多边形着上较为顺滑的渐变色,使其外观具有更强烈的实时感和立体动感,不过其着色速度比平面着色慢得多。
Gouraud 明暗处理,又称为强度插值明暗处理(intensity interpolation shading)。顾名思义,它是先根据三角形三个顶点的法矢量,和任意的光线模型,得出这三点的光强。然后,沿三角形的边和水平扫描线分别进行插值计算,得出这个三角形上的各点的光强。其示意图和公式如下:
其中I是光强,x和y是转换到二维视平面上的坐标。有了这个公式我们可以计算一个三角形上任意点的光强了。
局部光照模型之Lambert
Lambert光照模型是一个非常简单的模型,早在200多年前,一个叫Lambert的学者提出,当光照射到粗糙的表面时,它将向四周均匀的反射。这种各向同性的反射叫漫反射(Diffuse reflection)
漫反射光的强度服从于Lambert定律,漫反射的光强与入射光的方向和反射点处表面法向夹角的余弦成正比。Lambert模型的数学表达示如下:
Idiffuse = Kd*Id*cosθ
Kd表示物体表面漫反射属性,Id表时入射光强。若N表示入射点单位法向量,L表示从入射点指向光源的单位向量(注意是入射点指向光源,表示了入射光的方向),由点乘与cos之间的关系,cosθ = N●L,则Lmbert模型可表示为:
Idiffuse = Kd*Id*(N●L)
对应的Pixel Shader如下:
float4 main( float4 Diff : COLOR0,
float3 Normal : TEXCOORD0,
float3 View : TEXCOORD1,
float3 Light : TEXCOORD2,
float2 Tex : TEXCOORD4 ) : COLOR
{
// Compute ambient term:
float4 AmbientColor = ambient * Ka;
// Compute diffuse term:
float4 DiffuseColor = diffuse * Kd * max( 0, dot( Normal, Light ));
float4 FinalColor = (AmbientColor + DiffuseColor) * tex2D( baseMap, Tex);
return FinalColor;
}
局部光照模型之Phong
Lambert模型能很好的表示粗糙表面的光照,但不能表现出镜面反射高光。1975年Phong Bui Tong发明的Phong模型,提出了计算镜面高光的经验模型,镜面反射光强与反射光线和视线的夹角a相关:
Ispecular = Ks*Is*(cos a) n
其中Ks为物体表面的高光系数,Is为光强,a是反射光与视线的夹角,n为高光指数,n越大,则表面越光滑,反射光越集中,高光范围越小。如果V表示顶点到视点的单位向量,R表示反射光反向,则cos a可表示为V和R的点积。模型可表示为:
Ispecular = Ks*Is*(V●R) n
反射光放向R可由入射光放向L(顶点指向光源)和物体法向量N求出。
R = (2N●L)N – L
对应的Pixel Shader如下:
float4 main( float4 Diff : COLOR0,
float3 Normal : TEXCOORD0,
float3 View : TEXCOORD1,
float3 Light : TEXCOORD2,
float2 Tex : TEXCOORD4 ) : COLOR
{
// Compute the reflection vector:
float3 vReflect = normalize( 2 * dot( Normal, Light) * Normal - Light );
// Compute ambient term:
float4 AmbientColor = ambient * Ka;
// Compute diffuse term:
float4 DiffuseColor = diffuse * Kd * max( 0, dot( Normal, Light ));
// Compute specular term:
float4 SpecularColor = specular * Ks * pow( max( 0, dot(vReflect, View)), n_specular );
float4 FinalColor = (AmbientColor + DiffuseColor) * tex2D( baseMap, Tex) + SpecularColor;
return FinalColor;
}
局部光照模型之Blinn-Phong
图形学界大牛Jim Blinn对Phong模型进行了改进,提出了Blinn-Phong模型。Blinn-Phong模型与Phong模型的区别是,把V●R换成了N ●H,其中H为半角向量,位于法线N和光线L的角平分线方向。Blinn-Phong模型可表示为:
Ispecular = Ks*Is*(N●H) n
其中H = (L + V) / | L+V |,计算H比计算反射向量R更快速。
对应的PS如下:
float4 main( float4 Diff : COLOR0,
float3 Normal : TEXCOORD0,
float3 View : TEXCOORD1,
float3 Light : TEXCOORD2,
float2 Tex : TEXCOORD4 ) : COLOR
{
// Compute the reflection vector:
float3 H = normalize(View+Light);
// Compute ambient term:
float4 AmbientColor = ambient * Ka;
// Compute diffuse term:
float4 DiffuseColor = diffuse * Kd * max( 0, dot( Normal, Light ));
// Compute specular term:
float4 SpecularColor = specular * Ks * pow( max( 0, dot(H, Normal)), n_specular );
float4 FinalColor = (AmbientColor + DiffuseColor) * tex2D( baseMap, Tex) + SpecularColor;
return FinalColor;
}
效果图
从左到右,依次是Lambert、Phong、Blinn-Phong,可以看出Phong和Blinn-Phong都有高光,但两者还是有些区别的。
其他光照模型
Torrance-Sparrow model
Cook-Torrance model
Ward's anisotropic model
Oren–Nayar model
Ashikhmin-Shirley model
HTSG
Fitted Lafortune model
2. Phong Illumination(冯氏光照模型)浅析
很多人把冯氏光照(Phong Illumination)和冯氏渲染(phong shading)混淆到一起。冯氏渲染是指计算基于每像素的与表面相交的法向量的插值过程。你可以对每个像素做你喜欢的光照效果,或者对每个顶点做冯氏光照计算,在物体表面使用高洛德着色(Gouradu shading)。
冯氏光照是由Phong Bui-Tuong在1975年提出的.由于冯氏模型使用一般的文本比较难表示(主要是缺乏希腊字母),所以下面使用简称代替希腊字母所代替的意思:
Ix = 最终结果的色彩
Lx = 光照色彩
Ax = 环境光色彩
Dx = 漫反射色彩
Sx = 镜面反射色彩
Ka = 环境系数
Kd = 漫反射系数
Ks = 镜面反射系数
Att = 衰减系数
n = 光滑或者粗糙度
N = 物体表面的法向量
L = 指向光源的向量
R = 反射向量
V = 视点向量
下面就是冯氏模型:
Ix = Ax*Ka*Dx + Att*Lx[Kd*Dx( N dot L) + Ks*Sx(R dot V)^n]
Ix~Sx的值都含有组件值.对于RGB模型来说,这些组件值分别代表着(R,G,B)分量,范围为[0.0,1.0],所以这个模型对应的RGB解决方案如下:
Ir = ArKaDr + AttLr [KdDr(N dot L) + KsSr(R dot V)^n]
Ig = AgKaDg + AttLg [KdDg(N dot L) + KsSg(R dot V)^n]
Ib = AbKaDb + AttLb [KdDb(N dot L) + KsSb(R dot V)^n]
Ka~Ks这三个值范围为[0.0,1.0],一般作为材质(material)信息存储在材质表面定义中.Ka表示物体表面受环境光照影响的的程度.Kd表示物体自身反射光的程度.Ks表示光被反射后的强度.Att用于表示光线的衰减,指光源到物体光线的衰减.你可以定义另一个衰减表示物体到观察者之间光线的衰减.n用来判断镜面反射的范围,值越大,范围越小.这个值的选择主要靠经验,为了获得一个感性认识,可以试试3.0,200.0,和10000.0这几个值.
在冯氏渲染中,N是与表面相交的一个插值.在每个像素上,它被标准化用于冯氏光照等式上.L是指向光源的向量,R是被表面反射后的光向量,R的计算可以使用下面式子计算:
2N(N dot L) – L
V是从物体表面到观察者的向量.