Phong反射模型

发表日期:  Creative Commons Licence

http://www.snakehillgames.com/category/programming/

Phong reflection model

https://en.wikipedia.org/wiki/Phong_reflection_model

Phong反射模型包括了:

  • 环境光 Ambient lighting(可视为物体因为照射光反射而均匀作用在物体上呈现物体本身颜色的微弱光,即防止在没有光源的情况下物体呈现一团漆黑,通常为一常数值)
  • 漫反射光 Diffuse lighting(通常根据表面的法向量和光的法向量计算获得)
  • 高光 Specular lighting(一言难尽,详情见wiki)

Cel shading

卡通渲染(色块渲染),先给上代码:

diffuseLevel *= cellShadingLevel;
diffuseLevel = floor(diffuseLevel);
diffuseLevel /= cellShadingLevel - 0.5;

shader中的diffuseLevel是一个在0到1之间代表漫反射层级的数值。cellShadingLevel为整型的代表色彩层级数量的数值(最小为2)。在这段计算后,diffuseLevel通常会被叠乘在漫反射图像(diffuse map)上。

值得注意的是,存在着其他会影响diffuseLevel的参数,例如阴影(shadows),光的 衰减(attenuation),会在之后的阶段步骤中计算。

Warparound lighting

float diffuseLevel = clamp(dot(normal, lightVec), 0.0, 1.0);

当表面法向量与光向量同向时,diffuseLevel取值为1.0(默认所有向量都是单位向量,其中光向量的方向不是光的来向,而是光的来向的反向),当垂直时,diffuseLevel取值为0.0。但当相反时,可能会取到-1.0,为了避免这种情况,用clamp函数限制了取值范围在0.0到1.0之间。

Clamp (value : float, min : float, max : float) : float

限制value的值在min和max之间, 如果value小于min,返回min。 如果value大于max,返回max,否则返回value

透射光(Warparound lighting)为稍微反物理的变量,但实际上时环境光(Ambient lighting)的衍生,它允许除了完全与光向量相反的法向量之外的“物体背面”也能在光physics上照射不到的情况下获得一些微弱的光,以增加物体的表现力。透射光取值范围也为0.0到1.0之间的数值。可以将上面的shader改写为如下:

float diffuseLevel = clamp(dot(normal, lightVec) + lightWrap, 0.0, lightWrap + 1.0) / (lightWrap + 1.0);

Hemispheric ambience

通常不直接照射一种单色的环境光,而是将两种颜色相近的光照混合,来获取贴图的层次感。通常一种颜色会稍亮,另一种稍暗。在2d图片上,有这种混合实现方式:

float upFactor = normal.y * 0.5 + 0.5;
vec3 ambientResult = ambientLightColor * upFactor + ambientLightColor2 * (1.0 - upFactor);

y即为2d法线贴图中的“高度”。

Self-shadowing

float thisHeight = fragPos.z;
vec3 tapPos = vec3(centredTexCoords, fragPos.z + 0.01);
vec3 moveVec = lightVec.xyz * vec3(1.0, -1.0, 1.0) * 0.006;
moveVec.xy *= rotationMatrix;
moveVec.x *= textureResolution.y / textureResolution.x;
for (int i = 0; i < 20; i++)
{
   tapPos += moveVec;
   float tapDepth = 
             texture2D(depthMap, tapPos.xy).x * amplifyDepth;
   if (tapDepth > tapPos.z)
   {
      shadowMult -= 0.125;
   }
}
shadowMult = clamp(shadowMult, 0.0, 1.0);