@

1.坐标空间

我们在以前渲染流水线中就接触了坐标空间的变换。例如,在学习顶点着色器流水线阶段时,我们说过,顶点着色器的最基本功能就是把模型的顶点坐标从模型空间转换到齐次裁剪坐标空间中。

1.2 坐标空间的变换

我们先要为后面的内容做些数学铺垫。在渲染流水线中,我们往往需要把一个点或方向矢量从一个坐标空间转换到另一个坐标空间。这个过程到底是怎么实现的?
我们把问题一般化,我们知道,要想定义一个坐标空间,必须指明其原点的位置和三个坐标轴的方向。而这些数值实际上是相对于另一个坐标空间的(读者需要记住,所有的都是相对的)。也就是说,坐标空间会形成一个层次结构——每个坐标空间都是另一个坐标空间的子空间,反过来说,每个空间都有一个父(parent)坐标空间。对坐标空间的变换实际上就是在父空间和子空间之间对点和矢量进行变换。
假设现在有父坐标空间P以及一个子坐标空间C。我们知道父坐标空间中子坐标空间的原点位置以及3个单位坐标轴。我们一般会有两种需求:一种需求是把子坐标空间下表示的点或矢量Ac转换到父坐标空间下的表示Ap,另一个需求是反过来,即把父坐标空间下表示的点或矢量Bp转换到子坐标空间下的表示Bc。我们可以通过下面的公式来表示这两种需求:

其中,Mc->p表示的是从子空间转换到父空间的变换矩阵,而Mp->c是其逆矩阵(即反向变换)。那么现在的问题是,如何求解这些变换矩阵?事实上,我们只要求出二者之一即可,另一个矩阵可以通过求逆矩阵的方式来得到。
下面,我们来讲解如何来求出从子坐标空间到父坐标空间的变换矩阵Mc->p。
首先,我们来回顾一个看似很简单的问题:当给定一个坐标空间以及其中一点(a,b,c)时,我们是如何知道该点的位置呢?我们可以通过四个步骤来确定它的位置。
(1)从坐标原点开始
(2)向x轴方向移动a个单位
(3)向y轴方向移动b个单位
(4)向z轴方向移动c个单位
需要说明的是,上面的步骤只是我们的想象,这个点实际没有发生移动。上面的步骤看起来再简单不过了,坐标空间的变换就蕴含在上面的4个步骤中。现在,我们已知坐标空间C的三个坐标轴在父坐标空间P下的表示Xc,Yc,Zc,以及原来的原点Oc。当给定一个子坐标空间中的一点Ac=(a,b,c),我们同样可以依照上面4个步骤来确定其在父坐标空间下的位置Ap:
(1)从坐标的原点开始
这很简单,我们已经知道了子坐标空间的原点位置Oc。
(2)向x轴方向移动a个单位
仍然很简单,因为我们已经知道了x轴的矢量表示,因此可以得到

(3)向y轴方向平移b个单位
同样的道理,这一步就是:

(4)向z轴方向平移c个单位
最后就可以得到

现在,我们已经求出了Mc->p!什么?你没看出来吗?我们再来看一下最后得出的式子:

你们可能会问,这个式子里根本没有矩阵啊!其实,我么我们只要稍微使用一点魔法,矩阵就会出现在上面的式子中:

其中“|”符号表示是按列展开的。上面式子实际上就是使用了我们之前所学的数学公式而已。但这个最后的表达式还不是很漂亮,因为还存在加法表达式,即平移变换。我们已经知道了3×3矩阵无法表示平移变换,因此,为了得到一个更漂亮的结果,我们把上面的式子扩展到齐次坐标空间中,得


那么现在你看到Mc->p在哪里了吧,没错,

一旦求出来Mc->p,Mp->c就可以通过求逆矩阵的方式求出来,因为从坐标空间C变换到坐标空间P与从坐标空间P变换到坐标空间C是互逆的两个过程。
可以看出来,变换矩阵Mc->p实际上可以通过坐标空间C在坐标空间P中的原点和坐标轴的矢量表示构建出来:把3个坐标轴依次放入矩阵的前三列,把原点矢量放到最后一列,再用0和1填充最后一行即可。
需要注意的是,这里我们并没有要求3个坐标轴Xc、Yc和Zc是单位矢量,事实上,如果存在缩放的话,这三个矢量值很可能不是单位矢量。
更加令人振奋的是,我们可以利用反向思维,从这个变换矩阵反推来获取子坐标空间的原点和坐标轴方向。例如,当我们已知从模型空间到世界空间的一个4×4的变换矩阵,可以提取它的第一列再进行归一化后(为了消除缩放的影响)来得到模型空间的x轴在世界空间下的单位矢量表示。同样的方法也可以提取y轴和z轴。我们可以从另一个角度来理解这个提取过程。因为矩阵Mc->p可以把一个方向矢量从坐标空间C变换到坐标空间P中,那么,我们只需要用它来变换坐标空间C中的x轴(1,0,0,0),即使用矩阵乘法M->p[1 0 0 0]T,得到的结果正是Mc->p的第一列。
另一个有趣的情况是,对方向矢量的坐标空间变换。我们知道,矢量是没有位置的,因此坐标空间的原点变换是可以忽略的。也就是说,我们仅仅平移坐标系的原点是不会对矢量造成任何影响的。那么,对矢量的坐标空间变换就可以使用3×3矩阵来表示,因为我们不需要平移变换。那么变换矩阵就是:

在shader中,我们常常会看到截取变换矩阵的前3行前3列来对法线方向、光照方向来进行空间变换,这正是原因所在。
现在,我们再来关注Mp->c。我们前面讲到,可以通过求Mc->p的逆矩阵方式求解出来反向变换Mp->c。但有一种情况我们不需要求解逆矩阵就可以得到Mp->c,这种情况就是Mc->p是一个正交矩阵。如果它是一个正交矩阵的话,Mc->p的逆矩阵就等于它的转置矩阵。这意味着我们不需要进行复杂的求逆操作就可以得到反向变换。也就是说,如果我们知道坐标空间变换矩阵Ma->b是一个正交矩阵,那么我们可以提取它的第一列来得到坐标空间A的x轴在坐标空间B下的表示,还可以提取它的第一行来得到坐标空间B的x轴在坐标空间A下的表示。反过来,如果我们知道坐标空间B的x轴、y轴和z轴(必须是单位矢量,否则构建出来的就不是单位矩阵了)在坐标空间A下的表示,就可以把它们依次放在矩阵的每一行就可以得到A到B的变换矩阵了。

第三章 学习Shader所需的数学基础(2)的更多相关文章

  1. 第三章 学习Shader所需的数学基础(5)

    1. Unity Shader的内置变量(数学篇) 使用Unity写shader的一个好处在于,它提供了很多内置参数,这使得我们不在需要自己手动算一些值.本文给出Unity内置的用于空间变换和摄像机以 ...

  2. 第三章 学习Shader所需的数学基础(3)

    @[TOC] 1. 顶点的坐标空间变换过程 我们知道,在渲染流水线中,一个顶点要经过多个坐标空间的变换才能最终被画在屏幕上.一个顶点最开始是在模型空间中定义的,它最后会被变换到屏幕空间中,得到真正的屏 ...

  3. 第三章 学习Shader所需的数学基础(1)

    1. 笛卡尔坐标系 在游戏中,我们使用的数学大部分都是为了计算位置.距离和角度等变量.而这些就算大部分是在笛卡尔坐标系下进行的. 1.1 二维笛卡尔坐标系 一个二维笛卡尔坐标系包含了两个部分的信息 1 ...

  4. 第三章 学习Shader所需的数学基础(4)

    法线变换 法线(normal),也被称为法矢量(normal vector).在以前我们已经讲过如何使用变换矩阵来变换一个顶点或方向矢量,但法线是需要我们特殊处理的一种方向矢量.在游戏中,模型的顶点往 ...

  5. Unity Shader入门精要学习笔记 - 第4章 学习 Shader 所需的数学基础

    摘录自 冯乐乐的<Unity Shader入门精要> 笛卡尔坐标系 1)二维笛卡尔坐标系 在游戏制作中,我们使用的数学绝大部分都是计算位置.距离.角度等变量.而这些计算大部分都是在笛卡尔坐 ...

  6. 学习Shader所需的数学基础(坐标系,点和矢量)

    数学对于计算机图形学的重要性是不言而喻的.在学习Shader之前,首先就要打好数学基础,好在入门Unity Shader所需的数学知识都是线性代数中很基础的的内容.按部就班的来,第一篇文章记录总结的是 ...

  7. 《ORACLE数据库管理与开发》第三章学习之常用函数记录

    <ORACLE数据库管理与开发>第三章学习之常用函数记录 注:文章中的*代表所要操作的列名 1.lower(*)/upper(*),将此列下的值转为小写/大写 2.initcap(*):把 ...

  8. 《Linux内核设计与实现》第三章学习笔记

    第三章  进程管理 姓名:王玮怡  学号:20135116 一.进程 1.进程的含义 进程是处于执行期的程序以及相关资源的总称,程序本身并不是进程,实际上就是正在执行的代码的实时结果.Linux内核通 ...

  9. 20135202闫佳歆--week6 课本第三章学习笔记

    第三章 进程管理 一.进程 1.进程 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 进程是处于执行期的程序以及相关的资源的总称. 进程包括代码段和其他资源. 2.线程 执行线程, ...

随机推荐

  1. [Scala]Scala安装以及在IDEA中配置Scala

    一  Scala简述 Scala (斯卡拉)是一门多范式(multi-paradigm)的编程语言. 这里所谓的范式,指的是编写程序的方式,不同的编程语言,方式也不尽相同,也就意味着Scala编程语言 ...

  2. Pandas文本数据处理

    先初始化数据 import pandas as pd import numpy as np index = pd.Index(data=["Tom", "Bob" ...

  3. LNMP下zabbix_server安装部署一

    server:192.168.112.6 agent:192.168.112.7 安装nginx编译依赖包 gcc.pcre-devel.zlib-devel 如果需要https则加上openssl- ...

  4. LNMP+Redis

    如果要让php支持redis需要安装php-redis模块.可以再github上下载哦. https://github.com/phpredis/phpredis 配置lnmp环境,太简单了就不演示了 ...

  5. python学习之【第十六篇】:Python中的常用模块之OS模块、sys模块、random模块

    1. OS模块 OS模块是与操作系统交互的一个接口.内部提供了以下方法: os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname& ...

  6. P4409 [ZJOI2006]皇帝的烦恼(20190922B)(乱搞)

    考场历程十分艰辛啊... 第一题没切掉,还浪费了很长时间,就是一个裸的最小生成树,但是因为可恶的distance为关键字莫名其妙查错了10min.... 本题先乱搞了一下,过了样例 然后看第三题,可写 ...

  7. 七月月赛T2

    题目描述 “X龙珠”是一款益智小游戏.游戏中有 n(2∣n) 个编号互不相同龙珠按照给定的顺序排成一个队列,每个龙珠上面都有一个编号.每次操作时,选择并取出龙珠队列中相邻的两个龙珠,放到目标队列的末尾 ...

  8. ubuntu下minicom和usb串口转接

    ubuntu下minicom和USB转串口(转) (2013-03-23 21:07:54) 转载▼ 标签: it 分类: 嵌入式linux minicom是linux下串口通信的软件,它的使用完全依 ...

  9. 易初大数据 2019年11月2日 计算机英语 wangqingchao

    一.Match the explantions in Column B with words and expressions in Column A.(搭配每组中同意以的词或短语) 1.交换机(pos ...

  10. 微软的分布式应用框架 Dapr

    微服务架构已成为构建云原生应用程序的标准,微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合和独立部署,但是这种方法的成本很高,需要了解和熟练掌握分布式系统.为了使用所有开发人员能够使用任何 ...