Phong光反射模型解读

1、概述

该模型是一种模拟物体在光线下看起来什么样的方法,它把光分成3部分:环境光、漫反射光、镜面高光。

2、举例说明

拿着一个苹果站在灯下:

  • 整个房间是亮的,所以苹果不会完全黑掉  -> 环境光(Ambient)
  • 苹果被灯光照到的一面比较亮 -> 漫反射(Diffuse)
  • 苹果表面有个闪闪发亮的小点(像镜子一样反光) -> 镜面高光(Specular)

(1)环境光

想象你在室内,虽然灯不是正对着苹果,但苹果也不是全黑的。因为墙、地板、天花板会反射一些光,所以苹果还是有点亮。Phong用环境光来模拟“整体亮度”。

(2)漫反射

比如你用手电筒照苹果,正对着手电筒的那一面最亮。偏一点的角度,就暗一些。这个光是物体表面均匀反射的光,不光滑、不闪亮,但能看清物体的形状。

(3)镜面高光

苹果表面光滑的地方会出现一个“亮点”,这个亮点会随着你眼睛的位置变化而变化。越光滑的物体(比如玻璃、金属),这个高光越亮越集中。

用Phong模型可以:

  • 让角色在灯光下有明暗变化(漫反射)
  • 表面光滑的皮肤、金属武器的反光(镜面高光)
  • 让整个场景看起来不会太黑(环境光)

3、公式解读

(1)环境光部分

I_a = K_a * I_light
  • K_a:材质对环境光的反射能力(比如塑料、金属、纸张不一样)
  • I_light:环境光的强度(比如房间灯光)
float k_a = 0.6; // a value of our choice, typically between zero and one
vec3 i_a = vec3(0.7, 0.7, 0); // a color of our choice

vec3 ambient = k_a * i_a;

(2)漫反射部分

I_d = K_d * I_light * cosθ
  • K_d:材质的漫反射系数(越粗糙越容易漫反射)
  • I_light:光源强度
  • θ:光线和物体表面法线的夹角(cosθ就是点积)
  • cosθ = dot(N, L),N是法线的单位向量,L是光源方向的单位向量
vec3 p = ro + rd * d; // point on surface found by ray marching
vec3 N = calcNormal(p); // surface normal
vec3 lightPosition = vec3(1, 1, 1);
vec3 L = normalize(lightPosition - p);

float k_d = 0.5; // a value of our choice, typically between zero and one
vec3 dotLN = dot(L, N);
vec3 i_d = vec3(0.7, 0.5, 0); // a color of our choice

vec3 diffuse = k_d * dotLN * i_d;

(3)镜面反射部分

I_s = K_s * I_light * (cosα)^n
  • K_s:材质的镜面反射系数(越光滑越容易反光)
  • α:视线方向和反射方向的夹角
  • n:光泽度(越大,高光越集中)
vec3 p = ro + rd * d; // point on surface found by ray marching
vec3 N = calcNormal(p); // surface normal
vec3 lightPosition = vec3(1, 1, 1);
vec3 L = normalize(lightPosition - p);

float k_s = 0.6; // a value of our choice, typically between zero and one

vec3 R = reflect(L, N);
vec3 V = -rd; // direction pointing toward viewer (V) is just the negative of the ray direction

vec3 dotRV = dot(R, V);
vec3 i_s = vec3(1, 1, 1); // a color of our choice
float alpha = 10.;

vec3 specular = k_s * pow(dotRV, alpha) * i_s;

vec3 phong(vec3 lightDir, vec3 normal, vec3 rd) {
  // ambient
  float k_a = 0.6;
  vec3 i_a = vec3(0.7, 0.7, 0);
  vec3 ambient = k_a * i_a;

  // diffuse
  float k_d = 0.5;
  float dotLN = clamp(dot(lightDir, normal), 0., 1.);
  vec3 i_d = vec3(0.7, 0.5, 0);
  vec3 diffuse = k_d * dotLN * i_d;

  // specular
  float k_s = 0.6;
  float dotRV = clamp(dot(reflect(lightDir, normal), -rd), 0., 1.);
  vec3 i_s = vec3(1, 1, 1);
  float alpha = 10.;
  vec3 specular = k_s * pow(dotRV, alpha) * i_s;

  return ambient + diffuse + specular;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值