1.4 MVP矩阵

news2024/11/24 11:08:03

MVP矩阵代表什么

MVP矩阵分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。

 

我们的顶点坐标起始于局部空间(Local Space),在这里他成为局部坐标(Local Coordinates),它在之后会变为世界坐标(World Coordinates),观察坐标(View Coordinates),裁剪坐标(Clip Coordinates),并最后以屏幕坐标(Screen Coordinates)的形式结束。过程如下图所示

-------------------------------------------参考《Unity Shader入门精要》----------------------------------------

模型空间

模型空间(Model Space),或者说是对象空间(Object Space)、局部空间(Local Space)

模型空间原点和坐标轴通常是由美术人员在建模软件里确定好的,原点通常位于模型的中心。

世界空间

世界空间(World Space)是一个特殊的坐标系,因为他建立了我们所关心的最大空间。通常,我们会把世界空间的原点放置在游戏空间的中心。

将顶点坐标从模型空间变换到世界空间中,这个变换通常叫做模型变换

根据Transform组件上的信息,模型进行了(2,2,2)的缩放,又进行了(0,150,0)的旋转,以及(5,0,25)的平移。注意:这里的变换顺序不能互换。要按照先缩放,再旋转,最后平移,矩阵从右到左依次是缩放——旋转——位移矩阵。因此可以构建出模型变换的变换矩阵:

现在可以对目标物体进行模型变换了:

Pworld:世界空间下的目标点坐标。

Mmodel:模型变换矩阵。

Pmodel:模型空间下的目标点坐标。

也就是说世界空间下目标点位置是(9,4,18.072),注意这里的浮点数都是近似值。实际数值和Unity采用的浮点精度有关。

观察空间

观察空间(View Space)也被称为摄像机空间(Camera Space)。观察空间可以认为是模型空间的一个特例——在所有的模型中一个非常特殊的模型,即摄像机。

在Unity中的观察空间坐标轴选择是:+x轴指向右方,+y指向上方,+z指向的是摄像机后方。这里+z与模型空间和世界空间的+z相反,因为,Unity在模型空间和世界空间选用的是左手坐标系,观察空间使用的是右手坐标系。这是符合OpenGL传统的。

从世界空间变换到观察空间的过程叫做观察变换(View Transform)。

得到顶点在观察空间中的位置有两种方法:

①计算观察空间三个坐标在世界空间下的标识,然后构建出从观察空间到世界空间的变换矩阵,再对该矩阵求逆来得到从世界空间变换到观察空间的变换矩阵。

②想象平移整个观察空间,让摄像机原点位于世界坐标的原点,坐标轴与世界空间中的坐标轴重合即可。

采用第二种方法来计算变换。相机在世界空间中经过缩放->旋转->平移的到最终位置,所以逆变换需要以平移->旋转->缩放的顺序来计算。

由于观察空间是右手坐标系,所以要对z分量进行取反操作。

最后对顶点进行变换。

得到观察空间中目标顶点中的位置——(9, 8.84, -27.31)

裁剪空间

裁剪空间(Clip Space)也被成为齐次裁剪空间,这个用于变换的矩阵叫做裁剪矩阵(Clip Matrix),也被成为投影矩阵(Projection Matrix)。

裁剪空间的裁剪范围由视锥体(View Frustum)来决定,而视锥体又有两种类型,这涉及两种投影:一种是正交投影(Orthographic Projection),另一种是透视投影(Perspective Projection)。

在视锥体6块裁剪平面中,有两块裁剪平面比较特殊,分别是近剪裁平面(Near Clip Plane)远剪裁平面(Far Clip Plane)。它们决定了摄像机可以看到的深度范围。

投影矩阵将顶点转换到裁剪空间中,其目的有二:

    • 首先是为投影做准备。这是个迷惑点,虽然投影矩阵的名称包含了投影二字,但它并没有真正进行投影工作,而是再为投影做准备。真正的投影发生在后面的齐次除法(Homogeneous Division)过程中。而经过投影矩阵的变换后,顶点的w分量会具有特殊意义。
    • 其次是对x、y、z分量进行缩放。直接使用视锥体的6个才见平面来进行裁剪会比较麻烦。而经过投影矩阵缩放后,我们可以直接使用w分量座位一个范围值,如果x、y、z分量都位于这个范围内,就说明该顶点位于裁剪空间内。

透视投影

视锥体是由6个裁剪面所构成的,在Unity中,这6个裁剪平面则是由Camera组件中的参数和Game视图的横纵比共同决定。

由图看出,可以通过Camera组件的Field of View(简称FOV)属性来改变视锥体竖直方向的张开角度,而Clipping Planes中的Near和Far参数可以控制视锥体的近裁剪平面和远裁剪平面距离相机的远近。这样就可以求出视锥体近裁剪平面和远裁剪平面的高度,即:

现在还缺乏横向的信息。可以通过摄像机的横纵比得到。在Unity中,一个摄像机的横纵比由Game视图的横纵比和Viewport Rect中的W和H属性共同决定。假设前摄像机的横纵比为Aspect,则可以定义:

现在,我们可以根据已知的Near、Far、FOV和Aspect的值来确定透视投影的投影矩阵(P矩阵)。

一个顶点和上述P矩阵相乘后,可以有观察空间变换到裁剪空间中:

从结果看,这个投影矩阵本质就是对x、y和z分量进行不同程度的缩放(z分量还做了一个平移),缩放的目的是为了方便裁剪。注意,此时w分量不再是1,而是原先z分量的取反结果。现在就可以按如下不等式判断一个变换后的顶点是否位于视锥体内。如果一个顶点在视锥体内,那么他变换后的坐标必须满足:

任何不满足上述条件的图元都需要被剔除或者裁剪。

再见矩阵会改变空间转向性:空间从右手坐标系变换到了左手坐标系。这意味着离摄像机越远,z值越大。

正交投影

正交投影中的6个裁剪平面也是有Camera组件中的参数和Game视图的横纵比共同决定的。

正交投影的视锥体是一个长方形,因此计算上相比透视投影来说更加简单。由图可以看出,可以通过Camera组件的Size属性来改变视锥体竖直方向上高度的一般,而Clipping Planes中的Near和Far参数可以控制视锥体的金裁剪平面和远裁剪平面的远近。所以可以求出近远才见平面的高度:

设摄像机的横纵比为Aspect那么:

得到Near、Far、Size和Aspect的值,就可以确定正交投影的投影矩阵,如下:

同样,这里的投影矩阵是建立在Unity对坐标系的假定上面的。

一个顶点和上述投影矩阵相乘后的结果如下:

注意到,和透视投影不同的是,使用正交投影的投影矩阵对顶点进行变换后,w分量仍然为1。

本质:因为投影矩阵最后一行的不同,透视投影的投影矩阵的最后一行是【0 0 -1 0】,而正交投影矩阵的最后一行是【0 0 0 1】。这样做是为了在齐次除法上做准备。下一小节说明。

判断一个变换后的顶点是否为视锥体内使用的不等式和透视投影中的一样,这种通用性也是为什么要是用投影矩阵的原因之一。

屏幕空间

经过投影矩阵的变换后,就可以进行裁剪操作。当完成了所有裁剪工作后,就需要进行真正的投影了,也就是说,我们需要把视锥体投影到屏幕空间(Screen Space)。经过这一步变换,就会得到真正的像素位置,而不是虚拟的三维坐标。

屏幕空间是一个二维空间,因此,必须把顶点从裁剪空间投影到屏幕空间中,来生成对应的2D坐标。这个过程可以理解为两个步骤:

首先,需要进行标准齐次除法(Homogeneous Division),也被成为透视除法(Perspective Division)。实际上就是用齐次坐标系的w分量去除x、y、z分量。在OpenGL中,这一步得到的坐标叫做归一化设备坐标(Normalized Device Coordinates,NDC)。经过这一步可以把坐标从齐次裁剪坐标空间转换到NDC中。经过透视投影变幻后的裁剪空间,经过齐次除法后会变换到一个立方体内。在OpenGL的传统,这个立方体的x、y、z分量的范围都是【-1,1】。在DirectX中,z的分量范围是【0,1】。Unity则选了OpenGL这样的齐次裁剪空间。

对于正交投影来说,他的裁剪空间实际上已经是一个立方体了,w分量是1,所以齐次除法不会对顶点x、y、z产生影响。

经过齐次除法后,透视、正交投影的视锥体都变换到一个相同的立方体内。现在就可以根据变换后的x和y坐标来映射输出窗口的对应像素坐标(pixelWidth,pixelHeight)。

在Unity中,屏幕空间左下角的像素做标识(0,0),右上角像素坐标是(pixelWidth,pixelHeight)。由于当前x和y坐标都是【-1,1】,因此这个映射过程就是一个缩放过程。

齐次除法和屏幕映射的过程可以使用下面的公式来总结:

上面的式子对x和y分量都进行了处理,z分量一般会被用于深度缓冲。一个传统的方式是把

的值直接存进深度缓冲中,但这不是必须的。通常驱动生产商会根据硬件来选择最好的存储方式。此时clipw也并不会被抛弃,他回来后续一些工作中起到重要作用,例如进行透视校正差值。

验证过程可查看《UnityShader入门精要》4.6.8

世界空间的应用

不规则平面的Tilling:以世界坐标当做uv进行采样。

※P矩阵推导过程

--------------------------------------------------参考Games101 P4----------------------------------------------------

链接Lecture 04 Transformation Cont._哔哩哔哩_bilibili 时间轴:43:00

推导前定义的环境:

【camera】

  • camera再原点
  • 朝向-Z方向
  • Y轴为向上方向

正交投影

过程理解:

      • t、r、n、I、b、f是立方体的上下左右前后的范围。
      • 将包围盒经过平移->缩放(暂时不考虑旋转),映射到最右边一个标准的立方体上。
      • 由于是看向Z轴负方向,所以[f,n],远(f)的点数值小于近(n)的点
      • 右手坐标系来看

    1. 首先定义了立方体:y轴方向:t&b(上下);x轴方向:l&r(左右);z轴方向n&f(近远)此处n的数值>f(看向-Z方向,n离得近)
    2. 目的:
      • 把给定的定义好的立方体 映射到[-1,1]3标准立方体
      • 把左边的3个坐标轴分开考虑
      • x轴:(其他两个轴同理)
      • 写出x的范围表达式 → 重点:①映射到[-1,1]范围,②再写成线性表达式(ax+b)a就是缩放矩阵,b就是平移矩阵

过程理解:

      • 从右往左看,先看位移矩阵。
      • 如果是正常移出的话就是正的,将物体移回原点则前面加个负号。
      • (r+l)/ 2则是将对应轴移到原点上,其他轴坐标同理。
      • 2/(r-l),因为(r-l)是两点之间的距离,假如覆盖范围为1的话则可以得到(r-l)* x = 1,现在-1到+1区间是覆盖范围是2,所以的(r-l)* x = 2,所以得到x= 2/(r-l)

得到:Mortho=

 

透视投影

透视投影可以理解为将下图左边的平截头体通过“挤压”其右侧大的面,“挤压”成一个标准的立方体,例如图右的标准立方体。这样后续再求透视投影矩阵直接带入正交投影矩阵里就可以了。(因为正交投影矩阵相对来说计算简单)。

依旧是按右手坐标系来算

挤压后的特性:

    • 近平面上所有点不会变化
    • 远平面上所有点的z轴坐标不会发生变化
    • 远平面上的中心点任何坐标都不会变化

目的:

    • 先计算

      透视到正交的投影矩阵。
    • 再计算投影矩阵的到最终的投影矩阵。

假设从箭头方向看标记的两个点则横截面图如下:

由上图可知,根据相似三角形的特性,可以得到图右的公式。同理可以得到

想要一个挤压前的点转换到挤压后的点坐标,公式可以这样写:

因为Z前后关系不清楚,用unknown代替。

=>新概念引入

齐次坐标下的一个点(x,y,z,1)同时乘以一个常量k!=0,点不变,当k为z时具有同样的特性。

由此特性可以将矩阵中数全部乘以z得到

这样就可以知道:

所以可以知道此投影矩阵一部分数值:

此时回到开始定义的挤压后的特性:

近平面上所有点不会变化。

远平面上所有点的z轴坐标不会发生变化

则可以把矩阵中的z全部转换为n。所以挤压前的点=>挤压后的点

又根据齐次坐标系的性质,同时乘以一个数,点不变,则得到

所以由矩阵的第三行(0 0 A B)乘以得到的矩阵

(因为最后的到的n平方和x、y没有关系,因为是在近平面上计算的,所以前两个数值为0)

上面所计算的可以得到一下线性方程:

此时用到最后一个特性:远平面上的中心点任何坐标都不会变化。

要与上面点的映射一值所以这里需要同时乘以f。

计算所得两个线性方程:

带入可以得到透视到正交的投影矩阵:

Mpersp->ortho=

 

得到最终的透视矩阵则计算:

Mpersp=MorthoMpersp->ortho

又由于此为标准立方体,则可以得到t = -b,l = -r,且2t得到的是立方体高度h,2l得到的是立方体宽度w,h、w同时也是相机视口高宽,带入上式可化简为:

再次根据下图可以求得w、h、和FOV之间的关系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/749426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PHP面试题35】什么是MVC,为什么要使用它

文章目录 一、前言二、MVC介绍2.1 模型(Model)2.2 视图(View)2.3 控制器(Controller) 三、MVC模式的优点四、总结 一、前言 本文已收录于PHP全栈系列专栏:PHP面试专区。 计划将全覆盖PHP开发领域…

『分割』 平面模型分割

PCL提供的几个常见模型: pcl::SACMODEL_PLANE:平面模型,用于拟合平面结构的点云数据。 pcl::SACMODEL_SPHERE:球体模型,适用于拟合球体结构的点云数据。 pcl::SACMODEL_CYLINDER:圆柱体模型,用…

一个四年Android程序猿的2023上半年总结

一晃就做了四年的Android开发了,时光飞逝啊~ 工作的时间飞快,感觉每一天都很充实,但是大多数都是重复的样子。 去年的目标达成: 去年的目标就是学习学习,涨薪涨薪。上家公司的同事氛围很不错&#xff0…

一篇文章了解Redis分布式锁

Redis分布式锁 什么是分布式锁? ​ redis分布式锁是一种基于redis实现的锁机制,它用于在多并发分布式环境下控制并发访问共享资源。在多个应用程序或是进程访问共享资源时,分布式锁可以确保只有一个进程可以访问该资源,不会发生…

采用555时基电路的简易/可调定时长延时电路设计

采用 555 时基电路的简易长延时电路 本电路和一般的定时电路相比是通过在 555 时基电路的 5 脚处加了一个二极管 VD1,使得定时时间延长的特点。 一、电路工作原理 电路原理如图 11 所示。 当按下按钮SB时,12V的电源通过电阻器Rt向电容器Ct充电&#…

弹性IP和公网IP有什么区别?哪个好

​  弹性IP和公网IP有什么区别?哪个好。IP是服务器重要的组成资源,一台云服务器实例一般分为公网IP和内网IP,公网IP指的是对外访问的IP地址,是针对公众用户的IP,这是网站绑定的服务器IP地址。而内网IP顾名思义就是内部的网络IP…

Android Monkey稳定性测试

l 命令样例: adb shell monkey -p packagename --ignore-timeouts --ignore-crashes -v -v --throttle 200 1000000 各个参数的意义如下: -p 用此参数指定一个或多个包(Package)。指定包之后,Monkey将只允许系统启…

cmake多文件、多文件夹编译(2)

一、同级文件夹下代码调用问题 目录如下: ./testCMake(根目录): /build: /MyClass: CMakeLists.txt MyClass.cpp MyClass.h /MyFunction: CMakeLists.txt MyFunction.cpp MyFunction.h CMakeLists.txt main.cpp 上述…

day35-Postman/ajax

0目录 1.postman 2.ajax 1.Postman 1.1 定义:postman用于测试http协议接口,无论是开发还是测试人员 1.2 Servlet中的doGet()/daPost…

基于JavasSwing+MySQL的医药销售管理系统

点击以下链接获取源码: https://download.csdn.net/download/qq_64505944/87987881?spm1001.2014.3001.5503 功能:管理员与普通用户两个角色登录,可以增删改查用户,增删改查药品等功能 JDK1.8 MySQL5.7

微信小程序——开发入门

注册小程序 微信公众平台 设置相关信息 设置好之后需要去获取appID和秘钥,后序开发需要用到。 下载开发工具并安装 微信开发者工具(稳定版 Stable Build)下载地址与更新日志 | 微信开放文档 创建项目 打开开发者工具创建一个新项目并如下…

使用 ONLYOFFICE 宏检索网站详细信息

在上一篇文章中,我们基于一位用户发送的 VBA 参考构建了一个功能完善的 ONLYOFFICE 宏。今天,我们想再进一步,为其添加一些 Whois API 功能。 什么是 ONLYOFFICE 宏 如果您是一名资深 Microsoft Excel 用户,那么相信您已对于 VBA…

Nacos(服务注册与发现)+SpringBoot+openFeign项目集成

📝 学技术、更要掌握学习的方法,一起学习,让进步发生 👩🏻 作者:一只IT攻城狮 ,关注我,不迷路 。 💐学习建议:1、养成习惯,学习java的任何一个技术…

分割1——图像分割的前世今生

首先讲讲:什么是计算机视觉? 计算机视觉是一门让计算机学会“看”的学科,研究如何自动理解图像和视频中的内容。 其次讲讲:计算机视觉有哪些任务?我们所要讲的图像分割位于什么地位? 计算机视觉的三大经典…

计算机体系结构基础知识介绍之使用动态调度、多重问题和推测来利用流水线

我们已经了解了动态调度、多发射和推测等单独的机制是如何工作的。(具体请参见本人前几篇博客) 现在我们把这三种机制结合起来,得到一种和现代微处理器非常相似的微架构。为了简单起见,我们只考虑每个时钟周期发射两条指令的情况…

《算法竞赛·快冲300题》每日一题:“窗户”

《算法竞赛快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 窗…

es6 数组操作个人总结

es6 数组操作个人总结 动机数组数组生成可枚举对象转数组箭头函数筛选判断所有元素枚举循环 小结 动机 es6 ,说白了,就是增强版本的 js 。。。。。嗯,说到底,还是原生 js 罢了,不过比原有的 js 多了一些属性、类型、指…

【c++修行之路】智能指针

文章目录 前言为什么用智能指针智能指针简单实现unique_ptrshared_ptr 循环引用和weak_ptr的引入循环引用weak_ptr 定制删除器 前言 大家好久不见,今天来学习有关智能指针的内容~ 为什么用智能指针 假如我们有如下场景: double Div() {int x, y;cin …

Clion 配置Mingw64的 c++开发环境

1、Mingw64的安装与环境变量的配置 Mingw64文件下载 Mingw64下载地址:https://sourceforge.net/projects/mingw-w64/files/ posix相比win32拥有C 11多线程特性,sjlj和seh对应异常处理特性,sjlj较为古老,所以选择seh 配置环境变…

MongoDB踩过的坑

目录 启动MongoDB服务 可视化工具:MongoDB Compass 由于目标计算机积极拒绝,无法连接 BSONObj size: xxxx is invalid. Size must be between 0 and 16793600 (16MB) 启动MongoDB服务 1. 打开CMD 2. 进入安装MongoDB文件夹中的bin目录 3. mongod -…