齐次裁剪
通过透视投影得到的点[x齐次,y齐次,z齐次,w]形成的三角形片元,裁剪是在齐次}坐标中做裁剪的,即它是一个四维空间的裁剪。而不是经过透视除法后的立方体空间[x齐次/w,y齐次/w,z齐次/w,1]。
假设view空间中点P0(x,y,z)投影后齐次坐标P1(x′,y′,z′,w)
view空间到齐次坐标转换关系为
P1=MperspectiveP0
仿射变换不改变原来坐标系下顶点的属性(纹理,颜色)关系,所以可以直接线性插值。z’和z,y’和y,x’和x是线性关系。
P2(x′′,y′′,z′′,1)=(x′/w,y′/w,z′/w,1),x”与x不是线性的关系,x”与x,z有关系,经过透视除法后,不能使用线性插值,否则进行插值的纹理坐标或者颜色会不准确。
⎧⎩⎨⎪⎪⎪⎪−1≤x齐次/w≤1−1≤y齐次/w≤1−1≤z齐次/w≤1→⎧⎩⎨⎪⎪⎪⎪−w≤x齐次≤w−w≤y齐次≤w−w≤z齐次≤w
六个平面分别为
w=x齐次w=−x齐次w=y齐次w=−y齐次w=z齐次w=−z齐次
假设相机空间的二个点
a(x0,y0,z0,u0,v0,c0),
b(x1,y1,z1,u1,v1,color1),透视变换后齐次坐标的点
a′(x′0,y′0,z′0,w′0,u0,v0,c0),
b′(x′1,y′1,z′1,w′1,u1,v1,color1)
假设与-1左平面即
w=−x齐次,交点为
c′=a′+t(b′−a′),w,x分量为
(w′0+t(w′1−w′0),x′0+t(x′1−x′0))带入平面解得t,然后线性插值uvc。
固定yz。w=x和w=-x把平面分成二个区域。w<0说明在相机的背一侧。
光栅化
把透视除后的规格化设备坐标系按照窗口的长宽通过平移缩放变换到屏幕坐标系。
从一个投影场景生成网格颜色样本。1600宽,1200高的显示器有1 920 000个像素点。通常每个像素点会计算几次(深度比较),费时间。
FrameBuffer
Framebuffer是一个2D的图像,每个像素点都有颜色值。 用于显示在屏幕的图像数据。
光栅化一个三角形流程
- 确定被三角形覆盖的可见像素
- 计算三角形内的每个像素的颜色
- 确定像素的最终颜色并上传到framebuffer
黑色的代表完整的片元,灰色的代表不完整的片元。
如何把三角形变成片元?
可以采用扫描线,根据三角形凸的性质,水平扫描线从一段进入,另一端出去,在边缘和上下顶点处是部分片元。y最大值,最小值是三个顶点的最大值和最小值。
深度缓存
深度缓存用来确定可见的三角片,如果当前片元比原来的近,替换,否则不替换。但是当二个深度是一样时,会有显示问题。
缺点:
- 每个像素点有一个深度数组
- 在每一帧需要初始化为背景颜色,深度缓存为背景深度
以上二个硬件实现, 现在不是问题。对每一个片元的额外操作,计算深度值,查找深度缓存表,比较,写入如果符合。
zndc可以用来做深度值
假设视图空间一个三角形三角平面法向量n^=(a,b,c,),平面可以表示成ax+by+cz+d=0,d是一个固定常量。
平面上一点(xview,yview,zview)
该点在平面上,即:
axview+byview+czview+d=0
n^⋅(xview,yview,zview)+d=0
在NDC坐标中点(xndc,yndc)对应的视图空间坐标为一条射线
(xview,yview,zview)=tr=(xndc,yndc,−dist)tt≥0
dist表示到观察点到投影平面的距离。虽然能够对投影矩阵求逆,但是不能通过ndc坐标(即经过透视除法后的点)求的view的坐标。
视图空间的一个点投影在这个屏幕点上必定在这条射线上。
n^⋅(tr)+d=0→t=−dn^r
(xview,yview,zview)=tr=t(xndc,yndc,−dist)=−dn^⋅r(xndc,yndc,−dist)=−d(xndc,yndc,−dist)n^⋅(xndc,yndc,−dist)=−d(xndc,yndc,−dist)a∗xndc+b∗yndc−c∗dist→zview=d∗dista∗xndc+b∗yndc−c∗dist
{zview≥DepthBuffer更新片元zview<DepthBuffer不更新片元→⎧⎩⎨⎪⎪⎪⎪⎪⎪1zview≤DepthBuffer更新片元1zview>DepthBuffer不更新片元
但是直接求
zview有些复杂,我们使它的倒数,
1zview=a∗xndc+b∗yndc−c∗distd∗dist=(ad∗dist)xndc+(ad∗dist)yndc−cd
括号中为常数。
xndx,yndc到屏幕坐标
xs,ys的变换是一个仿射变换
即:
1zview=InvZ(xs,ys)=fxs+gys+h
根据forward difference
InvZ(xs+1,ys)−InvZ(xs,ys)=f(xs+1)+gys+h−(fxs+gys+h)=f InvZ(xs,ys+1)−InvZ(xs,ys)=fxs+g(ys+1)+h−(fxs+gys+h)=g
得到:
InvZ(xs+1,ys)=InvZ(xs,ys)+f InvZ(xs,ys+1)=InvZ(xs,ys)+g
通过这个公式,可以进行快速的
InvZ插值。
举个例子
常数
f=12.5,g=37.5
点
(4,0,100)正下方即金字塔第一条横线中间即以下4分别
(4,1,137.5),(4,2,175),(4,3,212.5),(4,4,250) zndc是
1zview的一个仿射变换(右手系,看向-z轴,归一化到[-1,1],
zndc=−n+fn−f−2nf(n−f)zview)
即
zndc=a+b1zview
假设n(10),f(1000)映射到0,1
zndc=−100099∗1zview+10099
zview
|
zndc
|
10 |
0.0 |
20 |
0.5 |
100 |
0.91 |
200 |
0.95 |
500 |
0.98 |
1000 |
1.0 |
可以看到zview20的时候用掉了50%的精度,100的时候还剩下10%的精度。即前面的距离相机进的地方精度高,远的地方精度低,而远的地方可以会导致前后的物体映射到同一个z_{ndc}上,导致z-fighting。
16位的浮点数表示65535个数。
纹理映射
以下纹理映射的一个例子,沿着视线的方向。
线框图
纹理
期望的纹理映射
采用仿射变换的纹理映射
通常颜色的插值可以直接用线性插值,因为人对颜色变化不敏感。即认为用xscreen,yscreen(xscreen,yscreen与xndc,yndc是线性关系)去插值片元的颜色。
我们需要用View空间的位置去插值,而不是用ndc空间的值去插值。
xndc,yndc与uzndc,vzndc成线性关系
假设投影在xz平面上,yz平面的退到也类似。
假设View空间的二个点A(Xview1,Zview1)B(Xview2,Zview2),直线方程为aX+bZ=c
投影平面的点p1,p2在ndc上的点为(xndc1,−d),(xndc2,−d)
根据三角形相似得到:
Xview1Zview=xndc1−d→Xview1=xndc1−dZview1
把该点(xndc1−dZview1,Zview1)带入直线方程aX+bZ=c得到:
axndc1−dZview1+bZview1=c→1Zview1=−adcxndc1+bc
同理另外一点为:
1Zview2=−adcxndc2+bc
假设
ps=p1+s(p2−p1),0<s<1即
ps((1−s)xndc1+sxndc2,−d) 1Zs=−adcxs+bc=−adc((1−s)xndc1+sxndc2)+bc=(1−s)(−adcxndc1+bc)+s(−adcxndc2+bc)=(1−s)1Zview1+s1Zview2
可以知道:
xndc与1Zview是线性关系,即xndc=A01Zview+B0,Zview=A1xndc+B1
在View空间中三角形纹理坐标(u,v)与空间中的点(X,Y,Z)呈线性关系,即
{Xview=A2u+B2Yview=A3u+B3
带入:
Xview=xndc−dZview
得到:
A2u+B2=xndc−dZview→A2uZview+B2Zview=−1dxndc−→−−−−−−−−−−−1Zview=A0xndc+B0A2uZview+B2(A0xndc+B0)=−1dxndc→uZview=Axndc+B
同理有
uZview=Ayndc+BvZview=Axndc+BvZview=Ayndc+B
纹理映射总结
xndc∼1ZviewXview∼uXview=xndc−dZview→uZview∼xndc
因为
xndc到屏幕是一个仿射变换,
xndc∼xscreen→uZview∼xscreen
对于屏幕上二个点
(xscreen1,yscreen1,zndc1,u1,v1),(xscreen2,yscreen2,zndc2,u2,v2),插值点,先通过
zndc1,zndc2插值得到z′ndc即1Z′view,根据u1zndc1,u2zndc2插值得到u′z′ndc,最后计算u′=u′z′ndcz′ndc
纹理滤波
通过纹理坐标取得纹理图像的值。
纹理放大,显示像素比纹理像素尺寸大。
纹理缩小,显示像素比纹理像素尺寸小。
纹理放大
通过上面计算的纹理坐标u,v([0,1])乘上纹理尺寸后uv会有小数,采样可以采用如下二种方法:
1. 最近邻插值
(uint,vint)=(floor(utexel+0.5),floor(vtexel+0.5))
2. 双线性滤波
左下角纹理坐标(uint,vint)=(floor(utexel),floor(vtexel))
(ufrac,vfrac)=(utexel−uint,vtexel−vint)
纹理缩小
3. Mipmapping
原始图像Image0尺寸
wtexture0=htexture0=2L
下一层
wtexture1=htexture1=2L−1
采样
image1(i,j)=I0(2i,2j)+I0(2i+1,2j)+I0(2i,2j+1)+I0(2i+1,2j+1)4
如何选择合适的一层?
∂utexel∂xscreen水平方向上每像素 纹素的变换
∂utexel∂yscreen垂直方向上每像素 纹素的变换
如果像素和纹素一一对应,一个近似的方法
(∂utexel∂xscreen)2+(∂vtexel∂xscreen)2=1
(∂utexel∂yscreen)2+(∂vtexel∂yscreen)2=1
假设取max那方向
size=max((∂utexel∂xscreen)2+(∂vtexel∂xscreen)2−−−−−−−−−−−−−−−−−−−−√,(∂utexel∂yscreen)2+(∂vtexel∂yscreen)2−−−−−−−−−−−−−−−−−−−√)
size2L=1→L=log(size)log2
作业
已知屏幕坐标系(1200*600),在片元中的三个点(属性分别为x,y,zndc,u,v)转换到屏幕坐标系中为A(100,100,1/2,0,0),B(200,100,1/3,0,1),C(100,200,1/4,1,0),采用邻近采样,纹理图像为灰度图像,大小为50*50,第0行纹理值全为0,第1行为1,…,第49行为49。求屏幕中(100,150)(即AC中点)的像素值。