【5】:三维到二维变换(模型、视图、投影)

观测变换

物体上某一点的坐标变换顺序:M->V->P

MVP变换用来描述视图变换的任务,即将虚拟世界中的三维物体映射(变换)到二维坐标中。

1.Model Transformation 模型变换

场景中每个物体上的某一点,从局部坐标系变换到世界坐标系,每个物体有自己独有的模型变换矩阵,代表物体独有的在世界坐标系中的位置。

2.View / Camera Transformation 视图变换

相机在世界坐标系中移动。对同一个相机,所有模型共用一个视图变换矩阵

3.Projection Transformation 投影变换

正交投影:投影区域为一个长方体,远近物体最终在屏幕上显示同等大小

透视投影:投影区域为一个梯台,近、远平面为两个缩放的长方体,四侧边线延迟交于相机,最终显示到屏幕为近大远小

MVP变换

MVP变换,就是Model模型、View观察、Projection投影变换三个单词的缩写。是图形学中将三维空间的物体呈现在二维屏幕上十分重要的三个变换。在学习MVP变换之前,首先要知道几个空间的概念。

视图变换 View / Camera Transformation

需要确定的参数

需要知道相机的位置,相机看向的方向,还需要知道相机的上方向

确定相机的上方向,相当于确定相机在手中拍照时旋转的角度

在变换之前的约定

因为相机与物体之间的相互位置不变时,相机与物体这对组合放在空间中的哪里是无关紧要的

比如相机与物体的位置组合是 (a1, b1) 和 (a2, b2) 这两组,只要 a1 与 b1 之间的相对位置与 a2 与 b2 之间的相对位置是相等的,那么 (a1, b1) 与 (a2, b2) 在相机拍摄出来的效果是一样的

然后有一个约定就是,相机始终在原点,相机始终指向 -Z

因为既然你这对组合在空间中是自由的嘛,所以我给其中一个顶死了,另外一个也定死了

我个人是感觉,为了方便一直处理一个数据对象,可以假设相机始终在

视图变换的步骤

1.将摄像机的中心移动到世界坐标原点

2.将摄像机的前方向 g 转动到世界坐标系的 -Z 方向

3.将摄像机的上方向 t 转动到世界坐标系的 Y 方向

此后,摄像机的右方向 g x t 自然是世界坐标系的 X 方向

要计算这个变换矩阵的具体形式时,分为两个矩阵来写

第一个矩阵是平移矩阵,写在连乘式的最左边

第二个矩阵是旋转矩阵,是 g 到 -Z,t 到 Y,g x t 到 X 的旋转矩阵

平移矩阵很好写,但是这个旋转矩阵不好写

因为是三个任意的轴旋转到三个固定的轴

虽然旋转矩阵不好写,但是这个旋转矩阵的逆矩阵好写

这个旋转矩阵的逆矩阵的意义是,-Z 到 g,Y 到 t,X 到 g x t

正交投影 Orthographic

因为在前面已经把相机的前方向指向了 -Z,那么只要将物体的 Z 坐标丢掉,得到的就是物体在 XY 面上的投影

最后得到的投影结果,约定要缩放到 [-1, 1]

一般性的正交投影的描述

约定要将一个长方体投影到正方体

各个面的描述

l 左边 left

r 右边 right

b 底部 bottom

t 顶部 top

n 近处 near

f 远处 far

在图示的右手系中,与一般的常识不同的是,距离我们比较近的 n 面,z 值比较大,距离我们比较远的 f 面,z 值比较小

opengl 在窗口空间(屏幕空间)中使用的左手系,就是为了方便符合 n 面的 z 值小,f 面的 z 值大

正交投影的变换式

首先是平移矩阵

要计算两个面之间中心,然后在这个面的方向上移动到原点

例如 (r+l)/2 是两个 x 方向上两个面之间的中心,然后 -(r+l)/2 就是把中心移动到 x = 0

然后是缩放矩阵

因为要缩放到的正方体的长度为 2,要覆盖 [-1, 1]。而原来的边长,也就是两个面之间的距离是两个面的坐标值相减

例如 x 方向上,原来的边长是 r-l,现在要缩放到 2,那么就是乘一个 2/(r-l)

透视投影 Perspective Projection

背景

欧式几何中的平行线在透视投影之后会相交

在齐次坐标中,(x,y,z,1), (kx,ky,kz,k) 表示同一个点

因此 (x,y,z,1), (xz,yx,z^2,z) 也表示同一个点

约定

约定与正交投影中类似的近面 n 远面 f

挤压视锥体到长方体的思路

透视投影是非常困难的,如果要直接写出来是不好理解的

好理解的做法呢,首先知道透视投影和正交投影的目标都是类似的,都是将一个区域投影到一个边长为 2 的正方体

假如拿远平面的四个点去挤压到近平面,它们在同一个高度上,它们给挤成一个空间中的长方体,做完这些操作以后就可以看到这些线经过这些正交投影给它投影到了了近平面上去。也就是说,讲透视投影拆成了两半:

1.先把远平面以及中间的这些位置给挤成长方体

2.再做一次正交投影

那么如果进行"挤"呢?有几点需要规定:1.近平面永远不变2.远平面的点z值不变仍然是f,仅仅是在这个平面内向里面收缩3.中心点挤了之后也不会变化

y'和y根据相似三角形得出,对于x也是同理。任何的z

新向量三个值都是已知的

为什么不是新向量的,也就是压缩之后的向量,的第三个维度的值不是保持为 z?

这是一种错觉,之前约定了 near 和 far 面的 z 值不变,就给人了一种感觉是,好像中间的点的 z 在压缩的时候也不会变,实际上是会变的

这个错觉的一个另一个可能的来源是,在计算压缩之后的 x 和 y 的值的时候,我们是使用旧面的 z 来参与相似三角形的计算

但是我使用旧面的 z 只是因为我在 x 和 y 上的变换值与近面是有这个联系的,不代表变换之后旧面不会动

然后我们保持这个新向量的第三个维度的值不知道

就已经可以知道这个变换矩阵的其他值了,就差变换矩阵的第三行不知道了

这一行不知道,所以一般的想法就是待定系数法来解

然后我们已知的条件是,近面和远面都不变,所以我们将近面和远面的点代入这个变换式,就可以解出

相关推荐
小春熙子17 小时前
Unity图形学之着色器之间传递参数
unity·游戏引擎·技术美术·着色器
YxVoyager4 天前
【OpenGL】OpenGL简介
c++·windows·图形渲染
杳戢5 天前
凹凸/高度贴图、法线贴图、视差贴图、置换贴图异同
unity·图形渲染·贴图·技术美术
小白的建模5 天前
如何让3dsMax渲染效果更逼真好看?
3d·图形渲染·3dsmax·vr
Padid6 天前
SRP 实现 Cook-Torrance BRDF
c++·笔记·unity·游戏程序·图形渲染·着色器
Frank学习路上8 天前
【C++】OGRE:面向对象图形渲染库配置与示例
c++·图形渲染·ogre
小春熙子14 天前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Padid16 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
refineiks22 天前
three.js绘制宽度大于1的线,并动态新增顶点
3d·图形渲染·webgl
Winston Wood24 天前
一个简单的例子,说明Matrix类的妙用
android·前端·图像处理·图形渲染