前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小议斜透视投影矩阵(oblique projection matrix)

小议斜透视投影矩阵(oblique projection matrix)

作者头像
用户2615200
发布2019-04-18 14:10:58
1K0
发布2019-04-18 14:10:58
举报
文章被收录于专栏:tkokof 的技术,小趣及杂念

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1414846

本文简介了斜透视投影矩阵(oblique projection matrix)相关的一些知识

Unity 的这篇文档提及了斜透视投影的一些内容,还列出了示例代码:

代码语言:javascript
复制
using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    void SetObliqueness(float horizObl, float vertObl) {
        Matrix4x4 mat  = Camera.main.projectionMatrix;
        mat[0, 2] = horizObl;
        mat[1, 2] = vertObl;
        Camera.main.projectionMatrix = mat;
    }
}

代码挺简单的,但是其中的原理文档中并未提及,本篇文章尝试简单讲解一下~

首先,我们要了解一下 Camera.projectionMatrix 这个矩阵的构成,简单起见,我们这里直接给出结论,有兴趣的朋友可以去看看完整的推导过程(很好的一篇文章,目前似乎还没有译文,有时间自己来翻译一下):

Unity 中的 Camera.projectionMatrix 遵循 OpenGL 的规范约定,正常的透视投影情况下,该矩阵的构成如下:

2nr−l0r+lr−l002nt−bt+bt−b000−f+nf−n−2nff−n00−10 \begin{bmatrix} \dfrac{2n}{r - l} & 0 & \dfrac{r + l}{r - l} & 0 \ 0 & \dfrac{2n}{t - b} & \dfrac{t + b}{t - b} & 0 \ 0 & 0 & -\dfrac{f + n}{f - n} & -\dfrac{2nf}{f - n} \ 0 & 0 & -1 & 0 \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎢⎢⎡​r−l2n​000​0t−b2n​00​r−lr+l​t−bt+b​−f−nf+n​−1​00−f−n2nf​0​⎦⎥⎥⎥⎥⎥⎥⎥⎤​

其中

  • lll 是左(垂直)裁剪面的坐标
  • rrr 是右(垂直)裁剪面的坐标
  • bbb 是下(水平)裁剪面的坐标
  • ttt 是上(水平)裁剪面的坐标
  • nnn 是近(深度)裁剪面的坐标
  • fff 是远(深度)裁剪面的坐标

正常的透视投影情况下,我们有:

r=−l  ⟹  r+l=0  ⟹  r−l=2r(1)t=−b  ⟹  t+b=0  ⟹  t−b=2t(2) \begin{aligned} & r = -l \implies r + l = 0 \implies r - l = 2r & \hspace{20 mm} (1)\ & t = -b \implies t + b = 0 \implies t - b = 2t & \hspace{20 mm} (2)\ \end{aligned} ​r=−l⟹r+l=0⟹r−l=2rt=−b⟹t+b=0⟹t−b=2t​(1)(2)​

所以上面的矩阵可以简化为:

nr0000nt0000−f+nf−n−2nff−n00−10 \begin{bmatrix} \dfrac{n}{r} & 0 & 0 & 0 \ 0 & \dfrac{n}{t} & 0 & 0 \ 0 & 0 & -\dfrac{f + n}{f - n} & -\dfrac{2nf}{f - n} \ 0 & 0 & -1 & 0 \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎡​rn​000​0tn​00​00−f−nf+n​−1​00−f−n2nf​0​⎦⎥⎥⎥⎥⎥⎤​

现在我们需要调整这个矩阵来达到斜透视投影的效果,怎么做呢?拿水平方向的斜透视举例,我们要做的其实就是 偏移(shift) 左(垂直)裁剪面的坐标右(垂直)裁剪面的坐标,即偏移上面矩阵中的 lll 和 rrr, 假设我们偏移 sss 个坐标单位,则有:

l′=l+s(3)r′=r+s(4) \begin{aligned} & l' = l + s & \hspace{20 mm} (3) \ & r' = r + s & \hspace{20 mm} (4) \ \end{aligned} ​l′=l+sr′=r+s​(3)(4)​

考虑最开始的透视投影矩阵,由于我们变更了其中的 lll 和 rrr(变更为了 l′l'l′ 和 r′r'r′),所以新的(斜)透视投影矩阵变为:

2nr′−l′0r′+l′r′−l′002nt−bt+bt−b000−f+nf−n−2nff−n00−10 \begin{bmatrix} \dfrac{2n}{r' - l'} & 0 & \dfrac{r' + l'}{r' - l'} & 0 \ 0 & \dfrac{2n}{t - b} & \dfrac{t + b}{t - b} & 0 \ 0 & 0 & -\dfrac{f + n}{f - n} & -\dfrac{2nf}{f - n} \ 0 & 0 & -1 & 0 \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎢⎢⎡​r′−l′2n​000​0t−b2n​00​r′−l′r′+l′​t−bt+b​−f−nf+n​−1​00−f−n2nf​0​⎦⎥⎥⎥⎥⎥⎥⎥⎤​

将之前的 (1),(2),(3),(4)(1),(2),(3),(4)(1),(2),(3),(4) 这四个等式代入计算,我们得到:

nr0sr00nt0000−f+nf−n−2nff−n00−10 \begin{bmatrix} \dfrac{n}{r} & 0 & \dfrac{s}{r} & 0 \ 0 & \dfrac{n}{t} & 0 & 0 \ 0 & 0 & -\dfrac{f + n}{f - n} & -\dfrac{2nf}{f - n} \ 0 & 0 & -1 & 0 \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎡​rn​000​0tn​00​rs​0−f−nf+n​−1​00−f−n2nf​0​⎦⎥⎥⎥⎥⎥⎤​

注意到相比之前简化的透视投影矩阵,只有一个矩阵元素发生了变化(第一行第三列,即M0, 2),从之前的 000 变为了 s/rs/rs/r,而 s/rs/rs/r 这个数值表示的则是(水平)倾斜度:

  • s/r=0s/r = 0s/r=0 即 s=0s = 0s=0,表示不进行偏移,即(水平)倾斜度为 000
  • s/r=1s/r = 1s/r=1 即 s=rs = rs=r,表示向右偏移整个右(垂直)裁剪面的坐标,即(水平)倾斜度为 111
  • s/r=−1s/r = -1s/r=−1 即 s=−r=ls = -r = ls=−r=l,表示向左偏移整个右(垂直)裁剪面的坐标,即(水平)倾斜度为 −1-1−1
  • 其他的一些数值情况即代表不同的(水平)倾斜度

垂直方向的斜透视也同样可以依此分析,假设垂直方向的偏移量为 s′s's′ 坐标单位,我们能够得到:

nr0000nts′t000−f+nf−n−2nff−n00−10 \begin{bmatrix} \dfrac{n}{r} & 0 & 0 & 0 \ 0 & \dfrac{n}{t} & \dfrac{s'}{t} & 0 \ 0 & 0 & -\dfrac{f + n}{f - n} & -\dfrac{2nf}{f - n} \ 0 & 0 & -1 & 0 \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎢⎡​rn​000​0tn​00​0ts′​−f−nf+n​−1​00−f−n2nf​0​⎦⎥⎥⎥⎥⎥⎥⎤​

可以看到,相比之前简化的透视投影矩阵,新的(斜)透视投影矩阵也仅有一个矩阵元素发生了变化(第二行第三列,即M1, 2),并且该元素的数值同样表示(垂直)倾斜度(s′/ts'/ts′/t).

综上,如果我们给定了 (水平)倾斜度(垂直)倾斜度,只要据此改变原透视投影矩阵的两个元素(设置 第一行第三列,即M0, 2 为(水平)倾斜度,设置 第二行第三列,即M1, 2 为(垂直)倾斜度)即可得到我们想要的斜透视投影矩阵~

讲到这里,如果再看一眼先前的示例代码的话,想必是一目了然了~

代码语言:javascript
复制
using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    void SetObliqueness(float horizObl, float vertObl) {
        Matrix4x4 mat  = Camera.main.projectionMatrix;
        mat[0, 2] = horizObl;
        mat[1, 2] = vertObl;
        Camera.main.projectionMatrix = mat;
    }
}
相关资料
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年04月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 相关资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档