图形学初识--透视修正

1,351 阅读3分钟

前言

前面章节讲解了面片剔除的内容,这一章节咱们补充一个比较关键的内容:透视矫正。主要包括:为什么?是什么?怎么做?,从这些角度考虑切入!

正文

为什么需要透视矫正?

通过前面章节三角形光栅化重心坐标插值的学习,可以很容易计算出屏幕空间中三角形内部所有点的属性值:f(P)=αf(A)+βf(B)+γf(C)f(P) = \alpha f(A) + \beta f(B) +\gamma f(C)

但是我们思考一个问题:屏幕空间坐标的重心坐标插值可以代替空间中三角形的情况么?

这个问题从以下两个坐标变换阶段分析:

  • 阶段一:视图坐标空间--->NDC坐标空间(只分析透视投影)
  • 阶段二:NDC坐标空间--->屏幕坐标空间

1、视图坐标空间--->NDC坐标空间(透视投影)

(1)直线:

我们先来看一个逆Y轴视角看的示意图:

在这里插入图片描述

假设一条直线 ABAB,投影到近平面上形成 ABA'B'ABAB 有一个中点 CC 投影到近平面上为 CC' ,那么我们很显然发现了CC' 不是 ABA'B' 的中点。

从而可知,由于这是逆y轴看,也就说明从视图坐标空间--->NDC坐标空间的X轴坐标出现失真!类似可得,Y轴坐标也出现了失真,Z轴暂且抛开不谈。

紧接着,咱们设AC/AB=dAC/AB=dA'C'/A'B' = d',AC/AB=d,可得以下等式:

f(C)=df(B)+(1d)f(A)f(C)=df(B)+(1d)f(A)f(C) = d*f(B) + (1-d)*f(A)\\ f(C') = d'*f(B') + (1-d')*f(A')

容易知道:f(A)=f(A)f(B)=f(B)f(A) = f(A'), f(B) = f(B'),同时根据上图可知d!=dd != d' ,所以可以得到f(C)!=f(C)f(C) != f(C')

也就是说线段 ABAB 中间的任何点的插值计算都会出现偏差。

(2)三角形:

根据上述的直线结论,咱们将其推广到三角形的中心坐标插值计算!

已知视图坐标空间SABCS_{ABC},对应的NDC坐标空间的SABCS_{A'B'C'}SABCS_{ABC}内任意一点 PP 对应NDC坐标空间为 PP',容易得到如下等式:

f(P)=αf(A)+βf(B)+γf(C)f(P)=αf(A)+βf(B)+γf(C)f(P) = \alpha f(A) + \beta f(B) + \gamma f(C)\\ f(P') = \alpha' f(A') + \beta' f(B') + \gamma' f(C')\\

容易知道:f(A)=f(A)f(B)=f(B)f(C)=f(C)f(A) = f(A'), f(B) = f(B'),f(C) = f(C') ,很容易得出ααββγγ\alpha和\alpha',\beta和\beta',\gamma和\gamma' 不全相等,所以可以得到 f(P)!=f(P)f(P) != f(P')

总结:

因此,我们得知视图坐标空间->NDC坐标空间,会发生失真,从而影响后续插值算法的计算,从而导致问题!

2、NDC坐标空间--->屏幕坐标空间

我们回顾以下,这个阶段总共做了两件事情:

  • 一:XYZ坐标范围从[1,1][-1,1],变换到[0,1][0,1]
  • 二:XY分别从[0,1][0,1] 变换到[0,screen_width][0,screen\_width][0,screen_height1][0, screen\_height -1]

(1)XYZ坐标范围从[1,1][-1,1],变换到[0,1][0,1]

我们很容易想到,这个事情是涉及到均匀缩放和平移,不会影响重心坐标插值等计算!如下图:

在这里插入图片描述

(2)XY分别从[0,1][0,1] 变换到[0,screen_width][0,screen\_width][0,screen_height1][0, screen\_height -1]

为了直观,这个事情要从两个过程考虑:

第一个过程: 1*1平行投影到一张纸上

第二个过程: 纵横统一缩放 screen_width/screen_heightscreen\_width/screen\_height

如下图所示:

在这里插入图片描述

这里我们知道第二个过程不会影响重心坐标插值等计算。但是过程一不好说,所以咱们来进行分析过程一!

我们先观察直线的平行投影,如下图所示:

在这里插入图片描述

由相似三角形,很容易得到等式 AO:BO=AO:BOAO:BO = A'O':B'O' ,因此可以知道O点在平行投影前后插值比例不变!

然后咱们看一下空间中三角形平行投影的情况,如下图所示:

在这里插入图片描述

先观察左边三角形ABC,结合之前重心坐标计算公式,可知:

αγ=SBCOSBAO=hcha\frac{\alpha}{\gamma} = \frac{S_{BCO}}{S_{BAO}} = \frac{h_c}{h_a}

根据相似三角形可以得到:

hcha=lcla\frac{h_c}{h_a} = \frac{l_c}{l_a}

所以可以得到:

αγ=lcla\frac{\alpha}{\gamma} = \frac{l_c}{l_a}

同理根据右边三角形,咱么可以得到:

αγ=lcla\frac{\alpha'}{\gamma'} = \frac{l_c'}{l_a'}

又因为直线AC在平行投影前后,线段比例保持不变的结论: la:lc=la:lcl_a:l_c = l_a':l_c'

所以咱们可以知道:

αγ=αγ\frac{\alpha}{\gamma} = \frac{\alpha'}{\gamma'}

同理,咱们可得:

αβ=αββγ=βγ\frac{\alpha}{\beta} = \frac{\alpha'}{\beta'}\\ \frac{\beta}{\gamma} = \frac{\beta'}{\gamma'}

所以最终得到:α:β:γ=α:β:γ\alpha:\beta:\gamma = \alpha':\beta':\gamma',又因为α+β+γ=1α+β+γ=1\alpha+\beta+\gamma=1且\alpha'+\beta'+\gamma'=1,最终可以得到:

α=αβ=βγ=γ\alpha = \alpha'\\ \beta = \beta'\\ \gamma = \gamma'\\

于是我们可知平行投影的操作不会影响插值的计算!

总结:

从NDC坐标变换到屏幕空间变换的过程中,不会发生插值计算失真的现象!不需要矫正!

综上:

我们只需要修正视图空间下的重心坐标到NDC空间下的重心坐标关系即可!

什么是透视矫正?

在NDC坐标空间下,已知 ABC\triangle{A'B'C'} ,且已知三角形内某点OO'的重心坐标为 (α,β,γ)(\alpha',\beta',\gamma')

在视图坐标空间下,已知 ABC\triangle{ABC} ,且已知三角形内某点OO的重心坐标为 (α,β,γ)(\alpha,\beta,\gamma)

通过上述分析可知,屏幕空间下计算的重心坐标结果和在NDC下一致。

所以问题可描述为: 通过屏幕空间下的重心坐标(α,β,γ)(\alpha',\beta',\gamma')求真正视图坐标空间下的重心插值坐标(α,β,γ)(\alpha,\beta,\gamma)

透视矫正如何实现?

公式推导

已知:视图坐标空间下ABC\triangle{ABC};NDC坐标空间下 ABC\triangle A'B'C',中间经过投影矩阵P和透视除法两个步骤,流程如下:

在这里插入图片描述

因此,同理可得:

A=(MA+twA)B=(MB+twB)C=(MC+twC)A'= \begin{pmatrix} \frac{M\vec{A} + \vec t}{w_A} \end{pmatrix}\\ B'= \begin{pmatrix} \frac{M\vec{B} + \vec t}{w_B} \end{pmatrix}\\ C'= \begin{pmatrix} \frac{M\vec{C} + \vec t}{w_C} \end{pmatrix}\\

注意:ABC为三维向量A'、B'、C'为三维向量

假设在NDC下有一个点OO',按照重心坐标公式:

O=αA+βB+γCO' = \alpha'\vec{A'}+\beta'\vec{B'}+\gamma'\vec{C'}

A,B,CA',B',C'分别代入,得到如下:

O=α(MA+twA)+β(MB+twB)+γ(MC+twC)O' = \alpha'\begin{pmatrix} \frac{M\vec{A} + \vec t}{w_A} \end{pmatrix}+\beta'\begin{pmatrix} \frac{M\vec{B} + \vec t}{w_B} \end{pmatrix}+\gamma'\begin{pmatrix} \frac{M\vec{C} + \vec t}{w_C} \end{pmatrix}

假设在视图坐标空间下有一个点OO​,按照重心坐标公式:

O=αA+βB+γCO = \alpha\vec{A}+\beta\vec{B}+\gamma\vec{C}

因为OO'也是由OO经过投影变换和透视除法而来,所以类似可得:

O=(MO+twO)O'= \begin{pmatrix} \frac{M\vec{O} + \vec t}{w_{O}} \end{pmatrix}\\

O\vec O 带入可得:

O=(M(αA+βB+γC)+twO)O'= \begin{pmatrix} \frac{M(\alpha\vec{A}+\beta\vec{B}+\gamma\vec{C}) + \vec t}{w_{O}} \end{pmatrix}\\

于是咱们结合上述的 OO' 的两个等式表达,可得:

O=α(MA+twA)+β(MB+twB)+γ(MC+twC)=(M(αA+βB+γC)+twO)\begin{align} O' &= \alpha'\begin{pmatrix} \frac{M\vec{A} + \vec t}{w_A} \end{pmatrix}+\beta'\begin{pmatrix} \frac{M\vec{B} + \vec t}{w_B} \end{pmatrix}+\gamma'\begin{pmatrix} \frac{M\vec{C} + \vec t}{w_C} \end{pmatrix}\\ &=\begin{pmatrix} \frac{M(\alpha\vec{A}+\beta\vec{B}+\gamma\vec{C}) + \vec t}{w_{O}} \end{pmatrix} \end{align}

由上述可得,适用于任何ABC取值,所以系数必须匹配相等,可得:

αwA=αwOβwB=βwOγwC=γwO\frac{\alpha'}{w_A} = \frac{\alpha}{w_O}\\ \frac{\beta'}{w_B} = \frac{\beta}{w_O}\\ \frac{\gamma'}{w_C} = \frac{\gamma}{w_O}\\

从而,咱们就得到了:

α=αwAwOβ=βwBwOγ=γwCwO\alpha = \frac{\alpha'}{w_A}w_O\\ \beta = \frac{\beta'}{w_B}w_O\\ \gamma = \frac{\gamma'}{w_C}w_O\\

这样就得到了重心坐标分别在视图坐标空间和NDC坐标空间的关系。此时就剩一个未知数wOw_O

又因为α+β+γ=1\alpha + \beta + \gamma = 1,咱们将上述的关系式带入,可得:

αwAwO+βwBwO+γwCwO=1\frac{\alpha'}{w_A}w_O+\frac{\beta'}{w_B}w_O+\frac{\gamma'}{w_C}w_O = 1\\

所以就得到:

1wO=αwA+βwB+γwC\frac{1}{w_O} = \frac{\alpha'}{w_A} + \frac{\beta'}{w_B} + \frac{\gamma'}{w_C}

咱们大功告成!

于是得到矫正后的重心坐标插值公式:

f(O)=αf(A)+βf(B)+γf(C)=αwAwOf(A)+βwBwOf(B)+γwCwOf(C)=wO(αwAf(A)+βwBf(B)+γwC(C))\begin{align} f(O) &= \alpha f(A) + \beta f(B) + \gamma f(C)\\ &= \frac{\alpha'}{w_A}w_O f(A') + \frac{\beta'}{w_B}w_O f(B') + \frac{\gamma'}{w_C}w_Of(C')\\ &= w_O(\frac{\alpha'}{w_A} f(A') + \frac{\beta'}{w_B} f(B') + \frac{\gamma'}{w_C}(C')) \end{align}

深度Depth插值探讨

什么是Depth

对于某个顶点的Z值,经过视图变换、投影变换、透视触发,然后变换成NDC坐标,再经过屏幕空间变换,变成[0,1][0,1] 范围内的值,就是Depth!

问题描述

Depth作为一个属性,能够直接用屏幕空间的重心坐标进行插值计算而来呢?

推导

我们先来考察以下,经过透视投影矩阵变换前后,z坐标和w坐标的情况:

pc=[1aspecttan(fovy0.5)00001tan(fovy0.5)0000f+nfn2fnfn0010](xeyeze1)p_c = \begin{bmatrix} \frac{1}{aspect*\tan(fovy*0.5)}&0&0&0\\ 0&\frac{1}{\tan(fovy*0.5)}&0&0\\ 0&0&-\frac{f+n}{f-n}&\frac{-2fn}{f-n}\\ 0&0&-1&0\\ \end{bmatrix} \begin{pmatrix} x_e\\y_e\\z_e\\1 \end{pmatrix}

z和w变化如下:

zc=f+nfnze+2fnfnwc=zez_c = -\frac{f+n}{f-n}z_e + \frac{-2fn}{f-n}\\ w_c = -z_e

然后观察以下zcz_c经过透视除法,得到ndc坐标如下:

zndc=f+nfn+2fnfn1zez_{ndc} = \frac{f+n}{f-n} + \frac{2fn}{f-n}\frac{1}{z_e}

为了简化,设 zndc=A+B1zez_{ndc} = A + B\frac{1}{z_e}

这里的证明我们用反证法,我们需要证明的结论是可以直接用屏幕空间下的重心坐标进行插值Z。

所以,我们假设不能用屏幕空间下的重心坐标进行插值Z,因此得到下列不等式:

zndcOαzndcA+βzndcB+γzndcCz_{ndcO} \neq \alpha' z_ndcA + \beta' z_ndcB + \gamma' z_ndcC

zndc=A+B1zez_{ndc} = A + B\frac{1}{z_e}公式带入,得到了关于视图坐标系下z的不等式:

A+B1zeOα(A+B1zeA)+β(A+B1zeB)+γ(A+B1zeC)A + B\frac{1}{z_eO} \neq \alpha'(A + B\frac{1}{z_eA}) + \beta'(A + B\frac{1}{z_eB}) + \gamma'(A + B\frac{1}{z_eC})

然后两边进行拆分括号,得到:

A+B1zeOA(α+β+γ)+BαzeA+BβzeB+BγzeCA + B\frac{1}{z_eO} \neq A(\alpha'+\beta'+\gamma') + B\frac{\alpha'}{z_eA} + B\frac{\beta'}{z_eB} + B\frac{\gamma'}{z_eC}

这时候因为α+β+γ=1\alpha'+\beta'+\gamma' = 1,所以可以得到:

B1zeOBαzeA+BβzeB+BγzeCB\frac{1}{z_eO} \neq B\frac{\alpha'}{z_eA} + B\frac{\beta'}{z_eB} + B\frac{\gamma'}{z_eC}

因为B不可能为0,所以两边同时除B:

1zeOαzeA+βzeB+γzeC\frac{1}{z_eO} \neq \frac{\alpha'}{z_eA} + \frac{\beta'}{z_eB} + \frac{\gamma'}{z_eC}

这时候我们想想透视投影矩阵应用前后,第4维分量w的变量情况,可以得知:ze=wcz_e = -w_c,带入得到

1wOαwA+βwB+γwC\frac{1}{w_O} \neq \frac{\alpha'}{w_A} + \frac{\beta'}{w_B} + \frac{\gamma'}{w_C}

我们发现,这个结论是我们已经证明相等的,所以假设不成立,所以结论成立!

总结

可以利用屏幕空间的重心插值坐标,直接对Depth属性进行插值。

结尾:喜欢的小伙伴可以点点关注+赞哦

希望对各位小伙伴能够有所帮助哦,永远在学习的道路上伴你而行, 我是航火火,火一般的男人!