光的模型
-
定向光源
-
点光源
- 位置相关
- 颜色
- 强度(与距离平方成反比)
-
聚光源
- 在点光源的基础上
- 圆锥形范围内
RGB颜色模型
三原色
- 用于显示器、电视机等发光设备
- 屏幕显示的 颜色空间(R, G, B, A)混合RGB颜色比例
- RGB相加色系
- 混合
C
1
=
(
R
1
.
G
1
.
B
1
,
A
1
)
,
C
2
=
(
R
2
,
G
2
,
B
2
,
A
2
)
C_1=(R_1. G_1. B_1, A_1), C_2=(R_2, G_2, B_2,A_2)
C1=(R1.G1.B1,A1),C2=(R2,G2,B2,A2)
C 3 = ( R 1 A 1 + R 2 A 2 , G 1 A 1 + G 2 A 2 , B 1 A 1 + B 2 A 2 ) C_3=(R_1A_1+R_2A_2, G_1A_1+G_2A_2, B_1A_1+B_2A_2) C3=(R1A1+R2A2,G1A1+G2A2,B1A1+B2A2) - 打印机里不适用RGB, 而是CMYK的相减色系
HSV/HSB
- H=Hue色度,0°-360°
- S=Saturation饱和度,0-100%
- V=Value明度,0-100%
Color in OpenGL
在RGBA模式,使用glColor*()来设置当前颜色
- 保存为状态直到下次调用
- 对于glColor{3 4}{f d}(x, y, z, a), x, y, a, z属于[0, 1]
- 一般的,渲染场景中的不发光物体,glColor设定了光的反射率
图形学中的光照模型
泛光模型
物体不但反射光源的光,还有别的物体的反射光
简单起见,考虑环境光,各个角度的光强度一样
L
a
=
K
a
I
a
L_a=K_aI_a
La=KaIa
K
a
K_a
Ka反射率
I
a
I_a
Ia光照强度
L
a
L_a
La代表反射的环境光,即人眼所能看到的从物体表面反射的环境光的亮度
漫反射
- 反射点P局部是平面dA(流形)
- 入射光柱dL(光子固定频率撞击)
- 法向量N,入射向量L,夹角
α
\alpha
α
Lambert漫反射模型
物体接受的光照与入射角度的余弦值成正比
L
d
=
k
d
⋅
I
⋅
(
n
⋅
l
)
L_d=k_d\cdot I\cdot (n\cdot l)
Ld=kd⋅I⋅(n⋅l)
n和l的内积即夹角余弦值大小
漫反射与观察角度无关
- 物体材质
- 点光源强度和距离
- 入射角度
- kd和I都可以是三原色
L d = K d ( I / r 2 ) m a x ( 0 , n ⋅ l ) L_d=K_d(I/r^2)max(0, n\cdot l) Ld=Kd(I/r2)max(0,n⋅l)
镜面反射
高光(Specular)
- 反射光符合反射定律
- 例如镜子,湖面
- 更一般的是光泽反射(Glossy)
- 镜面反射光和光源颜色一致
Phone模型(镜面反射)
高光:光滑物体某区域特别亮
- R是镜面反射方向
- V是观察方向
- 镜面反射比较集中
- 考虑R和 V的夹角的余弦值,按指数次方递减
L s = k s ( I / r 2 ) m a x ( 0 , c o s α ) p L_s=k_s(I/r^2)max(0, cos\alpha)^p Ls=ks(I/r2)max(0,cosα)p
Binn-Phone模型
把反射角与人眼观察的夹角替换成一个半角向量和法线向量的夹角
半程向量:
h
=
b
i
s
e
c
t
o
r
(
v
,
l
)
=
v
+
l
∣
v
+
l
∣
h=bisector(v, l)=\frac{v+l}{|v+l|}
h=bisector(v,l)=∣v+l∣v+l
L
s
=
k
s
(
I
/
r
2
)
m
a
x
(
0
,
c
o
s
α
)
p
=
k
s
(
I
/
r
2
)
m
a
x
(
0
,
n
⋅
h
)
p
L_s=k_s(I/r^2)max(0, cos\alpha)^p=k_s(I/r^2)max(0, n\cdot h)^p
Ls=ks(I/r2)max(0,cosα)p=ks(I/r2)max(0,n⋅h)p
Phone模型的缺陷:观察方向和反射方向不能大于90°
Blinn-Phone模型没有这个缺陷
光照计算
简单光照计算公式:泛光+漫反射+高光
L
=
L
a
+
L
d
+
L
s
=
K
a
I
a
+
K
d
(
I
/
r
2
)
m
a
x
(
0
,
n
⋅
l
)
+
k
s
(
I
/
r
2
)
m
a
x
(
0
,
n
⋅
h
)
p
L=L_a+L_d+L_s\\ =K_aI_a+K_d(I/r^2)max(0, n\cdot l)+k_s(I/r^2)max(0, n\cdot h)^p
L=La+Ld+Ls=KaIa+Kd(I/r2)max(0,n⋅l)+ks(I/r2)max(0,n⋅h)p
顶点的光照计算是在相机坐标下(透视之前)
- 法向量、入射角、视角
- 顶点着色器计算光照颜色
- 对于Phone Shading,计算在片元着色器
已知三角形顶点的光照颜色,内部点在光栅化阶段通过插值获得
着色方法(Shading)
按着色频率来划分着色方法
- 每个面计算(Flat Shading)
- 每个顶点计算(Gouraud Shading)
- 每个像素计算(Phone Shading)
- 其余的图元内部像素通过插值着色
flat shading
同一个面颜色相同
- 插入同样颜色值
- 速度快,但不适合光滑表面
按Binn-Phone模型计算一次光照颜色,向量外积计算面法向量
Gouraud shading
计算顶点的Binn-Phone模型光照(三次)
顶点法向量
N
→
(
v
)
=
∑
i
N
→
(
f
)
∣
∣
∑
i
N
→
(
f
)
∣
∣
\overrightarrow{N}(v)=\frac{\sum_i\overrightarrow{N}(f)}{||\sum_i\overrightarrow{N}(f)||}
N(v)=∣∣∑iN(f)∣∣∑iN(f)
Phone shading
计算三角形内每个点的Binn-Phone模型光照
对三角形内部点的法向插值,归一化
逐点计算光照
shading汇总
OpenGL中的着色
OpenGL支持两种shading
- void glShadeModel(GLenum mode);
- 默认是GL_SMOOTH,或者GL_FLAT。即Gouraud Shading或者flat shading
OpenGL Lighting
光源颜色:环境光(Ambient light)、漫反射(Diffuse light)、高光(Specular light)
物体反射比率:环境光(Ambient light)、漫反射(Diffuse light)、高光(Specular light)
物体(Emissive color)
光源和物体的RGB属性:
- 光源(R, G, B)代表三原色光强度
- 物体(R, G, B)代表三原色反射率
- ( L R , L G , L B ) 和 ( M R , M G , M B ) (L_R, L_G, L_B)和(M_R, M_G, M_B) (LR,LG,LB)和(MR,MG,MB),眼睛看到的是 ( L R × M R , L G × M G , L B × M B ) (L_R\times M_R, L_G\times M_G, L_B\times M_B) (LR×MR,LG×MG,LB×MB)
单独设置场景中物体的材质参数
- glMaterialfv(GL_FRONT, GL_AMBIENT, …);
- 顶点颜色=Emission Color+Light.ambient * Object.ambient + Light.diffuse * Object.diffuse * … + Light.specular * Object.specular * …
统一设置场景中物体材质(替代glMaterial())
- glEnable(GL_COLOR_MATERIAL)
- glColorMaterial(GL_FRONT. GL_AMBIENT_AND_DIFFUSE);
- …glColor();
- glDisable(GL_COLOR_MATERIAL);
法向量决定光照计算
提供物体坐标下的法向量
- glBegin(GL_TRIANGLES)
- glNormal3d( n x , n y , n z n_x, n_y, n_z nx,ny,nz)
- glVertex3d( v x , v y , v z v_x, v_y, v_z vx,vy,vz)
- …
- glEnd()
实际参与计算的是变换后的法向量
- 在ModelView变换后,在Projection变换前
- 平移对法向量无效
- 法向量变换矩阵 ( M T ) − 1 (M^T)^{-1} (MT)−1
#Enable Light Sources
每个光源具有属性:color, position, direction, …, specified by glLightfv()
例如:
-
GLfloat light_ambient[] = {0.0, 0.0, 0.0, 1.0};
-
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
-
GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
-
GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};
-
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
-
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
-
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
-
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
-
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_position);
最多使用8个光源,GL_LIGHT0, GL_LIGHT1, …
控制光源位置
- 固定光源Stationary Light
- 在gluLookAt(…)前设置光源位置
- 也可以PushMatrix; LoadIdentity; SetLight0; PopMatrix;
- 独立移动光源
- 在modelView矩阵后设置变动的光源位置
- 可以PushMatrix; (LoadIdentity;)glRotate; SetLight0; PopMatrix
- 光源和物体相对 物体固定
- 在modelview矩阵后设置光源位置
- glLightfv(GL_LIGHT0. GL_POSITION, (0, 0, 3));