3D Game Programming withDX11 学习笔记(一) 数学知识总结
在图形学中,数学是不可或缺的一部分,所以本书最开始的部分就是数学知识的复习。在图形学中,最常用的是矢量和矩阵,所以我根据前面三个章节的数学知识,总结一下数学知识。
一、矢量
数学中的矢量,拥有方向和长度。其实矢量和点在坐标系中的表示完全一致(笛卡尔坐标系为准),区分矢量和点的关键,我觉得就是做平移。点是不能用平移操作来保证一致的,比如点A(1,2,3)经过平移矢量(1,2,3)后就是B(2,4,6),此时就是一个新的点。但是矢量经过相同平移操作后,还是矢量(1,2,3),这是因为矢量表示的是 vector head相对于 vector tail的偏移,平移操作并不会改变这种偏移。
在矢量中一个关键就是坐标系,数学中的坐标系主要分为左手坐标系和右手坐标系。我时不时会弄混左手和右手坐标系,后来做了一个快捷的记忆:我的头是y方向,右手伸出来是x方向,那么如果z方向向前是正方向,那我就处于左手坐标系; 如果我的z方向向后是正方向,那我就处于右手坐标系。所以看起来我的脸决定了我的坐标系:)
矢量的数学操作主要是:加、减、乘三种操作,如果算上求模(求长度),那就是四种操作。A=(xa,ya,za), B=(xb,yb,zb)
加:A + B = (xa+xb, ya+yb, za+zb)
减:A - B = (xa-xb, ya-yb, za-zb)
乘:A *B = xaxb+yayb+zazb
模:||A||2= xa2 + ya2+za2
细心的会发现矢量乘的结果变成了一个数,确实,最终的结果就是一个数,其本质就是一种映射或者投影,表示的是A矢量在B矢量方向上的投影长度,矢量的乘可以用公式表示为:
A *B = ||A|| *||B|| * sinθ,其中θ为两个矢量的夹角(由于不熟悉博客的数学公式添加,只有先这写着了,后面熟练了再修改吧)
矢量中最常见的操作就是归一化,比如有一个矢量的序列{V0,v1,V2...},如何将这些矢量归一化为互相垂直的单位矢量?
这儿引入投影的一个表示:projn(V)= v . n/||n||, 表示的是v在n的单位矢量上的投影,那么对于矢量序列,我们可以这样进行正交归一化:
1)v0, v1,v2.......
2) w0 = v0;
3) w1 = v1 - projw0(v1)
4) w2 = v2 - projw0(v2) - projw1(v2)
........
根据上面的规律,可以得到正交化的规律:将当前矢量(第一个除外)去除在前面所有矢量上的分量(投影),得到的就是与前面各个适量正交的矢量。
最后我们将正交化的矢量进行归一化操作,即可得到一组正交归一化矢量序列。
矢量的最后一个知识点是:矢量的叉积,与矢量点积得到一个投影的结果值不同,矢量的叉积得到的是一个矢量,基本公式为:
AXB = (yazb -zayb, zaxb - xazb, xayb - yaxb),
单看公式看不出规律,不过可以这样理解:xyz, yzx, zxy,分别去掉x, y , z,最后的结果就是三个分量的第一项,然后交换得到三个分量需要减去的第二项
矢量的叉积的实际意义,就是求得一个和A/B两个矢量都垂直的矢量,这在图形学中,可以用来求解游戏对象的一些常用矢量, 比如上(up)/下(down)/左(left)/右(right)/前(forward)/后(back)这些矢量都是互相垂直的,可以利用矢量的叉积得到。注意在笛卡尔坐标系中,矢量的叉积都是左手定律决定方向的,所以AXB和BXA是刚好方向相反的两个等长矢量。
二、矩阵
在图形学中,我们会绘制各种各样的游戏实例,这些实例都是用基本的点(verts)和相关的贴图(textures)、材质(material)等共同设置渲染状态的。对于基本的顶点,常常需要做的一个基本操作就是变换:平移、旋转、缩放等。这些变换操作对应的就是矩阵的变换。
矩阵的定义就不再多说,就是一个nxm的同类元素的集合,通常这个元素就是数字(也可以为其他,这儿不再扩展)。
矩阵最基本的操作可以分为: 矩阵的乘, 矩阵的转置, 矩阵的行列式, 矩阵的逆
矩阵的乘积: C = AB ≠BA
C矩阵中的每个元素是Cij是A矩阵的i行和B矩阵j列的对应点积的结果,基于此可以得到A矩阵的列数和B矩阵的行数是相等的(不然怎么做点积....)
矩阵的转置AT,就是将矩阵的行和列对换,说的简单点就是一列一列的变,新的每列是以前矩阵的每行竖着排列(感觉就是重新排队)
矩阵的行列式,是一个比较重要的点,Aij作为行列式的代指,就是去除A矩阵的i行和j列后得到的行列式计算结果,整体的公式为:
detA = ∑j=1n A1j(-1)i+jdetA1j
可以看出矩阵的行列式计算就是一个递归的计算过程,一般在图形学中的计算不会超过4x4的维度,所以可以用笔算的方式来计算这些矩阵的行列式:)
基于行列式,可以得到一个新的矩阵: 邻接矩阵A*,基于基本的矩阵A可以得到一个新的矩阵CA,其中的元素Cij = (-1)i+jdetAij,则可以定义邻接矩阵为:
A* = CAT 基于邻接矩阵,我们可以得到矩阵A的逆矩阵A-1 :A-1 = A*/detA
三、变换矩阵
基于矩阵的定义,我们可以将图形学中的一些常见的变换转化为对应的变换矩阵,这样在对点或者矢量进行变换的时候,其对应的数学操作就是一个变换矩阵的操作。基本的变换矩阵可以分为:缩放矩阵, 平移矩阵,旋转矩阵。
对于变换矩阵对矢量的作用,可以这样理解:u =(x,y,z) = xi + yj + zk, 那么一个变换操作可以表示为τ(u) = τ(xi + yj + zk) = xτ(i) + yτ(j) + zτ(k) = [x y z] [τ(i) τ(j) τ(k)]T = uA
所以说的直白点,就是用矩阵A来表示一种变换操作。那么具体如何表示呢?可以分拆为基本矩阵,然后进行合并即可。
1、缩放矩阵S
拆开用行向量表示为S(i) = (sx .1, sy.0, sz.0), S(j) = (sx .0, sy.1, sz.0),S(k) = (sx .0, sy.0, sz.1)
则缩放矩阵可以表示为S = [si , sj, sk]T, si = (sx,0,0), sj = (0,sy,0), sk = (0,0,sz)
2、旋转矩阵R
其实旋转矩阵是三个矩阵中相对比较难的矩阵,这儿给出一个旋转公式:
Rn(V) = projn(v) + Rn(V⊥)
= (n v) n + cosθ V⊥ + sinθ (n x v)
= cosθ V + (1 - cosθ)(n v)n + sinθ(n x v)
具体的常用的三个旋转矩阵可以列出来:



3、平移矩阵T
平移矩阵比较简单,就不做推算,直接给出结果即可:

综合三种基本矩阵,我们可以进行组合得到一个较为复杂的变换矩阵。不过在图形学的计算中,对于三种矩阵的排序有一定的讲究,一般先用缩放矩阵S对当前的变换对象进行缩放,然后用旋转矩阵R进行旋转操作,最后用平移矩阵T进行平移操作,所以可以归并为SRT矩阵。
总结:经过基本的矢量,矩阵和变换的数学知识总结后,接下来就要进入正式的图形学知识了,我会在后面持续更新~
3D Game Programming withDX11 学习笔记(一) 数学知识总结的更多相关文章
- MyBatis:学习笔记(1)——基础知识
MyBatis:学习笔记(1)--基础知识 引入MyBatis JDBC编程的问题及解决设想 ☐ 数据库连接使用时创建,不使用时就释放,频繁开启和关闭,造成数据库资源浪费,影响数据库性能. ☐ 使用数 ...
- C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)
一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字 ...
- C#学习笔记(基础知识回顾)之值传递和引用传递
一:要了解值传递和引用传递,先要知道这两种类型含义,可以参考上一篇 C#学习笔记(基础知识回顾)之值类型和引用类型 二:给方法传递参数分为值传递和引用传递. 2.1在变量通过引用传递给方法时,被调用的 ...
- C#学习笔记(基础知识回顾)之值类型和引用类型
一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...
- JAVA学习笔记—review基本知识[反射与异常]
JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...
- Quartz学习笔记:基础知识
Quartz学习笔记:基础知识 引入Quartz 关于任务调度 关于任务调度,Java.util.Timer是最简单的一种实现任务调度的方法,简单的使用如下: import java.util.Tim ...
- CUDA Programming Guide 学习笔记
CUDA学习笔记 GPU架构 GPU围绕流式多处理器(SM)的可扩展阵列搭建,每个GPU有多个SM,每个SM支持数百个线程并发执行.目前Nvidia推出了6种GPU架构(按时间顺序,详见下图):Fer ...
- .net学习笔记---xml基础知识
一.XML简介 XML是一种标记语言,用于描述数据,它提供一种标准化的方式来来表示文本数据.XML文档以.xml为后缀.需要彻底注意的是XML是区分大小写的. 先从一个简单的XML例子来了解下xml基 ...
- react学习笔记1--基础知识
什么是react A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES[React是一个用于构建用户界面的JavaScript库.] React之所以快, ...
随机推荐
- Python之matplotlib学习(一)
小试牛刀 在上一节已经安装好matplotlib模块,下面使用几个例子熟悉一下. 对应的一些文档说明: http://matplotlib.org/1.3.1/api/pyplot_summary.h ...
- npm -v;报错 cannot find module "wrapp"
1.node -v正常.npm-v就报错.. 说明:在官网上下载了安装了好几次.一用到npm就报这个错.园友们,我不太懂node,你们遇到这个问题怎么解决的? 2.报错 cannot find mod ...
- 【Python】三个例子教你写代码
这篇文章包括用Python编写的斐波那契数列,三位数的水仙花数和百钱买百鸡的基础代码: (一)斐波那契数列: ''' def hanshu(n): n_1 = 1 n_2 = 1 m = n sumn ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- 向maven中添加本地jar包
<dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java& ...
- Numpy入门 - 生成数组
今天是Numpy入门系列教程第一讲,首先是安装Numpy: $ pip install numpy numpy是高性能科学计算和数据分析的基础包,本节主要介绍生成连续二维数组.随机二维数组和自定义二维 ...
- 从a标签传值中文乱码解决
<% out.print(new String(request.getParameter("a标签的参数").getBytes("iso8859-1"), ...
- Python中的选择排序
选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大 ...
- Swift 线程安全数组
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:BigNerdCoding 有并发的地方就存在线程安全问题,尤其是对于 Swift 这种还没有内置并发支持的语言来说线程安全问题更为突出 ...
- ibv_get_device_name()函数
const char *ibv_get_device_name(struct ibv_device *device); 描述 函数用来获取一个与RDMA设备相关联的名字 注意 这个名字在一台特定的机器 ...