作业3以及相关知识的笔记
本课程的主页:https://sites.cs.ucsb.edu/~lingqi/teaching/games101.html
着色
光照模型
经典的光照模型(不是基于物理的,是基于经验的,因为看起来像) ,分成三部分,高光,漫反射和环境光
Lambetian
漫反射模型
L
d
=
k
d
(
I
/
r
2
)
m
a
x
(
0
,
n
∗
l
)
L_d=k_d(I/r^2)max(0,n*l)
Ld=kd(I/r2)max(0,n∗l)
其中
k
d
k_d
kd是系数,不同的材料会有不同的系数,
I
I
I是光照强度,
r
2
r^2
r2是距离,
I
/
r
2
I/r^2
I/r2是光照的强度。根据光照的方向也会有个强度,当光照为负向的时候,漫反射为0.
除了漫反射还有环境光(ambient),使场景更加真实:
L
a
=
k
a
I
a
L_a=k_aI_a
La=kaIa
Phong
在 Lambetian的基础上,phong加入了高光(specular)高光通常用在类似金属这种材料上:
L
s
=
k
s
(
I
/
r
2
)
m
a
x
(
0
,
v
∗
R
)
p
L_s=k_s(I/r^2)max(0,v*R)^p
Ls=ks(I/r2)max(0,v∗R)p计算反射光和眼看向物体的角度的偏移(反射向量在之前笔记中也有过推导)。高光项最后的系数是为了让高光范围更小,突变更明显。
Blinn-Phong
phong模型中反射光的计算量较大,Blinn-Phong使用了所谓"半程向量“进行了优化::
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
,
n
∗
h
)
p
L_s=k_s(I/r^2)max(0,n*h)^p
Ls=ks(I/r2)max(0,n∗h)p
总结光照模型:
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*l)+k_s(I/r^2)max(0,n*h)^p
L=La+Ld+Ls=kaIa+kd(I/r2)max(0,n∗l)+ks(I/r2)max(0,n∗h)p
着色频率
逐顶点还是逐像素的区别,逐顶点的话,中间的值就使用插值
渲染管线
这里只介绍了最基本的,也是所有光栅化管线都要有的步骤
输入顶点和拓扑,进行mvp变换,变换到对应位置
把顶点连成三角形
采样找到屏幕上的对应图形的像素点
逐像素进行模板测试,应用光照模型(顶点阶段也可以)等
对buffer进行操作(个人理解使进行msaa等操作)
纹理映射
纹理有自己的坐标系,纹理上的任何一个点都可以用(u,v)来表示,uv都是0到1之间的值,每个点读取纹理上每个像素的值
图片放大
当所给图片小于我们要显示的尺寸,一般来说寻址方式不同,可以重复,不重复,拉伸等方式。要放大图片时,中间的部分使用双线性插值,就是在xy轴上都平均,找周围的4个点。
mipmap
当从很远看一个物体,我们不希望看清它的细节(加载内存,以及采样原因),但是又需要能看清物体,这时使用mipmap。mipmap将原图纹理缩小到 1 / 4 1/4 1/4,然后不断重复,就得到了只有不到原图 3 4 \frac{3}{4} 43大小的mipmap。使用时我们找到一个点上方和左方临近的像素点,并找到他们在纹理山的对应的点,求出距离 l l l(两者最大的距离),这就求出了一个像素所能表示的范围,然后再通过 l o g 2 l log_2 l log2l来找到对应的mipmap的层数(例如一个像素表示的纹理范围是2x2,就在mipmap第一层,缩小了一次)。
凹凸贴图(bump map)
定义相对高度的移动,不改变模型,做假的法线,改变着色结果。如果是二维的情况下,法线是与切线垂直,先用差分法求切线,两个点的y方向的差值除以两点之间的距离(这里是1),最后乘上一个常数(控制凹凸的剧烈程度):
d
p
=
c
∗
(
h
(
p
+
1
)
−
h
(
p
)
)
d_p=c*(h(p+1)-h(p))
dp=c∗(h(p+1)−h(p))然后求法线,将x,y对调,y前加负号,最后归一化:
n
=
(
−
d
p
,
1
)
.
n
o
r
m
a
l
i
z
e
d
(
)
n=(-d_p,1).normalized()
n=(−dp,1).normalized()三维情况也类似,要分别求出两个方向上的切线,然后再转化成法线:
d
p
/
d
u
=
c
1
∗
(
h
(
u
+
1
)
−
h
(
u
)
)
d_p/d_u=c_1*(h(u+1)-h(u))
dp/du=c1∗(h(u+1)−h(u))
d
p
/
d
v
=
c
2
∗
(
h
(
v
+
1
)
−
h
(
v
)
)
d_p/d_v=c_2*(h(v+1)-h(v))
dp/dv=c2∗(h(v+1)−h(v))
n
=
(
−
d
p
/
d
u
,
−
d
p
/
d
v
,
1
)
.
n
o
r
m
a
l
i
z
e
d
(
)
(
未
推
导
)
n=(-d_p/d_u,-d_p/d_v,1).normalized()(未推导)
n=(−dp/du,−dp/dv,1).normalized()(未推导)
先用局部坐标,默认法线都是(0,0,1),进行计算之后再转换到世界坐标中。
位移贴图
位移贴图和凹凸贴图是相同的输入,但是会真的移动顶点的位置,凹凸贴图没有改变真正的几何图形,会在一些地方露馅(自己投影自己的阴影)。位移贴图要求三角形比较细,顶点间的间隔要比纹理的频率高。
三维纹理
噪声纹理,纹理的阴影自遮蔽(环境光遮蔽)(用纹理存储信息)