渲染管线理解4

齐次裁剪

通过透视投影得到的点 [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有关系,经过透视除法后,不能使用线性插值,否则进行插值的纹理坐标或者颜色会不准确。
这里写图片描述
1x/w11y/w11z/w1wxwwywwzw

六个平面分别为
w=xw=xw=yw=yw=zw=z

假设相机空间的二个点 a(x0,y0,z0,u0,v0,c0) , b(x1,y1,z1,u1,v1,color1) ,透视变换后齐次坐标的点 a(x0,y0,z0,w0,u0,v0,c0) , b(x1,y1,z1,w1,u1,v1,color1)
假设与-1左平面即 w=x ,交点为 c=a+t(ba) ,w,x分量为 (w0+t(w1w0),x0+t(x1x0)) 带入平面解得t,然后线性插值uvc。
这里写图片描述
固定yz。w=x和w=-x把平面分成二个区域。w<0说明在相机的背一侧。

光栅化

把透视除后的规格化设备坐标系按照窗口的长宽通过平移缩放变换到屏幕坐标系。
从一个投影场景生成网格颜色样本。1600宽,1200高的显示器有1 920 000个像素点。通常每个像素点会计算几次(深度比较),费时间。

FrameBuffer

Framebuffer是一个2D的图像,每个像素点都有颜色值。 用于显示在屏幕的图像数据。
这里写图片描述

光栅化一个三角形流程

  1. 确定被三角形覆盖的可见像素
  2. 计算三角形内的每个像素的颜色
  3. 确定像素的最终颜色并上传到framebuffer
    这里写图片描述这里写图片描述这里写图片描述
    这里写图片描述
    黑色的代表完整的片元,灰色的代表不完整的片元。
    如何把三角形变成片元?
    可以采用扫描线,根据三角形凸的性质,水平扫描线从一段进入,另一端出去,在边缘和上下顶点处是部分片元。y最大值,最小值是三个顶点的最大值和最小值。

深度缓存

这里写图片描述
深度缓存用来确定可见的三角片,如果当前片元比原来的近,替换,否则不替换。但是当二个深度是一样时,会有显示问题。
缺点:

  1. 每个像素点有一个深度数组
  2. 在每一帧需要初始化为背景颜色,深度缓存为背景深度

以上二个硬件实现, 现在不是问题。对每一个片元的额外操作,计算深度值,查找深度缓存表,比较,写入如果符合。

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)tt0
dist表示到观察点到投影平面的距离。虽然能够对投影矩阵求逆,但是不能通过ndc坐标(即经过透视除法后的点)求的view的坐标。
视图空间的一个点投影在这个屏幕点上必定在这条射线上。
n^(tr)+d=0t=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)axndc+byndccdistzview=ddistaxndc+byndccdist

{zviewDepthBufferzview<DepthBuffer1zviewDepthBuffer1zview>DepthBuffer

但是直接求 zview 有些复杂,我们使它的倒数,
1zview=axndc+byndccdistddist=(addist)xndc+(addist)yndccd
括号中为常数。
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+fnf2nf(nf)zview )

zndc=a+b1zview
假设n(10),f(1000)映射到0,1
zndc=1000991zview+10099

zview zndc
10 0.0
20 0.5
100 0.91
200 0.95
500 0.98
1000 1.0

可以看到 zview 20的时候用掉了50%的精度,100的时候还剩下10%的精度。即前面的距离相机进的地方精度高,远的地方精度低,而远的地方可以会导致前后的物体映射到同一个z_{ndc}上,导致z-fighting。
16位的浮点数表示65535个数。

纹理映射

以下纹理映射的一个例子,沿着视线的方向。
线框图
这里写图片描述
纹理
这里写图片描述
期望的纹理映射
这里写图片描述
采用仿射变换的纹理映射
这里写图片描述
通常颜色的插值可以直接用线性插值,因为人对颜色变化不敏感。即认为用 xscreen,yscreen ( xscreen,yscreenxndc,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=xndc1dXview1=xndc1dZview1
把该点 (xndc1dZview1,Zview1) 带入直线方程 aX+bZ=c 得到:

axndc1dZview1+bZview1=c1Zview1=adcxndc1+bc

同理另外一点为:
1Zview2=adcxndc2+bc

假设 ps=p1+s(p2p1),0<s<1 ps((1s)xndc1+sxndc2,d)
1Zs=adcxs+bc=adc((1s)xndc1+sxndc2)+bc=(1s)(adcxndc1+bc)+s(adcxndc2+bc)=(1s)1Zview1+s1Zview2

可以知道:
xndc 1Zview 是线性关系,即 xndc=A01Zview+B0,Zview=A1xndc+B1
在View空间中三角形纹理坐标(u,v)与空间中的点(X,Y,Z)呈线性关系,即
{Xview=A2u+B2Yview=A3u+B3

带入:
Xview=xndcdZview
得到:
A2u+B2=xndcdZviewA2uZview+B2Zview=1dxndc1Zview=A0xndc+B0A2uZview+B2(A0xndc+B0)=1dxndcuZview=Axndc+B

同理有
uZview=Ayndc+BvZview=Axndc+BvZview=Ayndc+B

纹理映射总结

xndc1ZviewXviewuXview=xndcdZviewuZviewxndc

因为 xndc 到屏幕是一个仿射变换,
xndcxscreenuZviewxscreen
对于屏幕上二个点 (xscreen1,yscreen1,zndc1,u1,v1),(xscreen2,yscreen2,zndc2,u2,v2) ,插值点,先通过 zndc1,zndc2zndc1Zview,u1zndc1,u2zndc2uzndc,u=uzndczndc

纹理滤波

通过纹理坐标取得纹理图像的值。
纹理放大,显示像素比纹理像素尺寸大。
纹理缩小,显示像素比纹理像素尺寸小。

纹理放大

通过上面计算的纹理坐标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)=(utexeluint,vtexelvint)
这里写图片描述
这里写图片描述

纹理缩小

这里写图片描述
3. Mipmapping
这里写图片描述
原始图像Image0尺寸
wtexture0=htexture0=2L
下一层
wtexture1=htexture1=2L1
采样
image1(i,j)=I0(2i,2j)+I0(2i+1,2j)+I0(2i,2j+1)+I0(2i+1,2j+1)4
如何选择合适的一层?
utexelxscreen 水平方向上每像素 纹素的变换
utexelyscreen 垂直方向上每像素 纹素的变换
如果像素和纹素一一对应,一个近似的方法
(utexelxscreen)2+(vtexelxscreen)2=1
(utexelyscreen)2+(vtexelyscreen)2=1
假设取max那方向
size=max((utexelxscreen)2+(vtexelxscreen)2,(utexelyscreen)2+(vtexelyscreen)2)
size2L=1L=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中点)的像素值。

猜你喜欢

转载自blog.csdn.net/a352614834/article/details/78370576