Phong模型

1) 向量定义(对应图中几何关系)
P:表面上一点(当前像素/片元的位置)N:该点的单位法线(图中虚线方向),N = normalize(N)L:光照方向(从点P指向光源LightPos)
L = normalize(LightPos - P)V:视线方向(从点P指向相机/眼睛ViewPos,图中右上)
V = normalize(ViewPos - P)R:反射方向(镜面反射方向,用于高光)
R = reflect(-L, N)
说明:reflect(I, N)里I是"入射方向",这里入射光是从光源打到表面点,方向可写成-L。
2) Phong 三项:环境光 + 漫反射 + 镜面反射
Phong 模型把最终颜色/亮度写成: I = I_ambient + I_diffuse + I_specular
(1) 环境光 Ambient(不考虑方向,给整体一个底色)
I_ambient = Ka * IaKa:材质环境系数(可用颜色vec3)Ia:环境光强/环境光颜色(全局常量或场景参数)
(2) 漫反射 Diffuse(Lambert),取决于入射角(图中箭头与法线夹角)
- 夹角余弦:
NdotL = max(dot(N, L), 0) I_diffuse = Kd * Il * NdotLKd:材质漫反射系数/底色Il:光源颜色/强度
(3) 镜面反射 Specular(Phong 高光),取决于观察方向与反射方向的接近程度
RdotV = max(dot(R, V), 0)I_specular = Ks * Il * (RdotV ^ shininess)Ks:材质镜面系数(高光颜色/强度)shininess:高光指数(越大高光越小越"硬")
常见细节:当 dot(N, L) <= 0 时,镜面项通常也置 0(背光面不产生高光):
if (NdotL <= 0) spec = 0
3) 点光源距离衰减(图里像是点光源,更真实)
若光源是点光源,强度随距离减弱:
d = length(LightPos - P)atten = 1 / (kc + kl*d + kq*d*d)- 把
I_diffuse、I_specular乘上atten
4) 最终合成(按颜色通道 vec3 计算)
Color = Ka*Ia + atten * (Kd*Il*NdotL + Ks*Il*pow(RdotV, shininess))- 最后可
clamp(Color, 0, 1)或做 HDR/色调映射(看你的渲染管线)
cpp
#version 330 core
in vec3 vFragPos;
in vec3 vNormal;
out vec4 FragColor;
uniform vec3 uViewPos;
uniform vec3 uLightPos;
uniform vec3 uLightColor;
uniform vec3 uObjectColor;
uniform float uShininess; // 如 32.0
void main() {
vec3 N = normalize(vNormal);
vec3 L = normalize(uLightPos - vFragPos);
vec3 V = normalize(uViewPos - vFragPos);
vec3 R = reflect(-L, N);
float diff = max(dot(N, L), 0.0);
float spec = pow(max(dot(R, V), 0.0), uShininess);
vec3 ambient = 0.1 * uLightColor;
vec3 diffuse = diff * uLightColor;
vec3 specular = 0.3 * spec * uLightColor;
vec3 color = (ambient + diffuse + specular) * uObjectColor;
FragColor = vec4(color, 1.0);
}

Blinn-Phong模型

在phong模型的基础上,改变高光的计算,不使用反射向量,取而代之的是半程向量H:H = normalize(L + V)
几何意义:
H是L和V的角平分方向。当N越接近H,越容易出现高光。
- 镜面反射(替换为 Half Vector):
I_specular = Ks * Il * (max(dot(N, H), 0) ^ shininess)
其他项计算和phong模型的计算一致。
cpp
#version 330 core
in vec3 vFragPos;
in vec3 vNormal;
out vec4 FragColor;
uniform vec3 uViewPos;
uniform vec3 uLightPos;
uniform vec3 uLightColor;
uniform vec3 uObjectColor;
uniform float uShininess; // 如 32.0
void main() {
vec3 N = normalize(vNormal);
vec3 L = normalize(uLightPos - vFragPos);
vec3 V = normalize(uViewPos - vFragPos);
vec3 H = normalize(L + V);
float diff = max(dot(N, L), 0.0);
float spec = pow(max(dot(N, H), 0.0), uShininess);
vec3 ambient = 0.1 * uLightColor;
vec3 diffuse = diff * uLightColor;
vec3 specular = 0.3 * spec * uLightColor;
vec3 color = (ambient + diffuse + specular) * uObjectColor;
FragColor = vec4(color, 1.0);
}

