《3D Math Primer for Graphics and Game Development》读书笔记1
《3D Math Primer for Graphics and Game Development》读书笔记1
本文是《3D Math Primer for Graphics and Game Development》第一版的读书笔记。第二版貌似还没有中文版。
本书网站gamemath.com。中文版居然给了翻译公司的网址,而且里面还什么有用的都没有,囧。
第2章 笛卡尔坐标系统
左手坐标系的记忆方法
伸出左手,手指依次是())))))Z轴。他们分别对应起来,用左手摆成下图的样子(不错的pose啊),就是左手坐标系。
右手坐标系的记忆方法
同上,用右手就行了。
约定俗成和习惯
传统的计算机图形学使用左手坐标系,线性代数则倾向于右手坐标系。
两种坐标系没有优劣之分,只是使用习惯不同。
本书使用左手坐标系。
第3章 多坐标系
摄像机坐标系
本书约定的摄像机坐标系,摄像机在原点,X轴向右,Z轴向前,Y轴向上,如下图所示。
许多图形学书中习惯使用右手系,Z轴向外,即从屏幕指向读者。
坐标系变换
坐标系变换的意思:知道某一点P在坐标系A中的坐标,如何获取P在另一坐标系B中的坐标?
只需在坐标系A中定位坐标系B(描述B的原点和轴在A中的值)。后文会详述。
包围盒
向量轴对齐包围盒是axially aligned bounding box(AABB)的翻译。我就是觉得包围盒这个翻译很不错。
第4章 向量
相对位置
"50英里每小时的速度向北"能用向量表示。
向量能描述的是相对位置。相对位置的想法是很直接的:某个物体的位置,能通过描述它与已知点之间的相对关系来指明。
由此引出一个问题,这些"已知"点在哪儿?什么是"绝对"位置?令人吃惊的是不存在这样的东西。因为在描述一个点的位置时,总要描述它和其它一些点的关系。这就没完没了了。
既然"已知"点不存在,那么如何通过所谓的"已知"点来描述位置呢?我的思路是:假设存在一个已知点的位置。假设已经找到了一个已知点,这样就不必无限地去追溯"已知"点了。
相对论的一个重要观点就是不存在绝对参考系。
第5章 向量运算
向量和点的关系
向量[x, y]描述了原点到点(x, y)的位移量。
向量和点在概念上不同,而在数学上等价。
等价是什么意思?等价就是两者存在一一对应的关系。一一对应是什么意思?就是即使你和我毫不相干,但是你有一个什么东西,我就有一个相应的什么东西;反过来也一样。比如你在照镜子,你看到镜子里的人脸上粘个米粒,就知道自己什么情况了。
向量投影
给定两个向量v和n,可以把v分成两部分:v||和v⊥。它们分别平行和垂直于n, 并满足v = v|| + v⊥。我们把平行分量v||称作v在n上的投影。
投影的计算公式:
垂直分量的公式:
后文会有很多地方用到这两个公式。总之你知道有这两个公式存在就行了,需要的时候拿来用。毕竟不需要做数学家。
第6章 3D向量类
类接口
好的类设计首先要回答下列问题:"这个类将提供什么操作?"、"在哪些数据上执行这些操作?"
从这些代码和设计思路中就可以感受到作者的认真态度和深厚功底。
设计决策
如果世界不超过1英里,那么32位的float类型就足够,因为24位尾数能提供1/250英寸的精度。
如果世界超过200英里(321.8688千米),比如整个江苏省,那么32位float就不够了。
不存在Point3类
有了Vector3类,就不需要Point3类。避免重复代码以及满世界的向量与点的转换。
关于优化
过早的优化是一切罪恶的根源。优化那些非瓶颈的代码,使代码复杂化,却没有得到相应的回报。
在过去,定点数是一种优化技术。当今的处理器已经可以快速处理浮点数,这个技术就不需要了。
不要为了2%的优化付出100%的代码复杂性。
简单点说,就是别优化,我的技术水平没那么高。
第7章 矩阵
矩阵用来描述两个坐标系间的关系,通过定义一种运算来将一个坐标系中的向量/点转换到另一个坐标系中。换句话说,就是已知一个向量/点在坐标系A中的坐标,又知坐标系A和坐标系B的关系,求其在坐标系B中的坐标。
向量是标量的数组,矩阵是向量的数组。
矩阵的下标从1开始。
矩阵乘法
记r×n矩阵A与n×c矩阵B的乘积为C。C的任意元素Cij如下:
矩阵乘法设计成这样,是因为有实际意义,数学上也有研究价值。或者说,正是因为它反映了现实世界的某些东西,才会有数学意义。
本书给了一种非常好的记忆方法:
我扩展了一下,可以将A的各个列拆开,同时将B的各个行拆开:
变成下图所示的样子:
可以看到,矩阵的乘法运算,可以把A的各列拆开,B的各行拆开,分别运算,最后相加。拆分时,只要A的列和B的行的拆分方式相同即可。
还有另一种拆法:把A的各行拆开,B的各列拆开,分别运算,最后拼起来。
而且,还可以同时进行这两种拆分。这时,你可以看做先进行第一种拆分,然后进行第二种拆分,这样(对我来说)比较容易理解。这样就能理解矩阵分块计算的原理。
约定和习惯
本书默认使用行向量进行与矩阵的运算。
DirectX使用的是行向量。
OpenGL使用的是列向量。
线性变换
线性变换保留了模型中原有的直线和平行线,原点也保持不动。长度、角度、体积可能会改变。从非技术意义上说,线性变换可能"拉伸"坐标系,但不会"弯曲"或"卷折"坐标系。
旋转、缩放、投影、镜像是线性变换。
仿射(线性变换后平移)不是线性变换。
方阵能描述线性变换。
矩阵运算和3D变换
设有一组基向量p0=(1, 0, 0),q0=(0, 1, 0),r0=(0, 0, 1),此时向量v=(x, y, z)就是v在p0=(1, 0, 0),q0=(0, 1, 0),r0=(0, 0, 1)这个坐标系里的坐标,即有v = xp0 + yq0 + zr0。
设p、q、r为任意一组基向量。例如p=(1, 0, 0),q=(0, 1, 0),r=(0, 0, 1)(互相垂直);或p=(0.8, 0.6, 0),q=(-0.6, 0.8, 0),r=(0, 0, 1) (互相垂直);或p=(1/√5)(2,-1,0),q= (1/√45)(2,4,5),r= (1/3)(1,2,-2) (互相垂直)或p=(1, 1, 1-√2 ),q=(1-√2, 1, 1),r=(1, 1-√2, 1)(并非互相垂直)……
然后,我们用p、q、r构造矩阵。没什么理由,就这么做了。
来看看向量v=(x, y, z)乘以矩阵会出现什么?
从左边到第一个等号右边,说明这个乘法运算给v赋予了新的坐标值。废话。
从第一个等号右边到第二个等号右边,说明这个新的坐标值与基向量p、q、r的关系等同于v与原始基向量p0=(1, 0, 0),q0=(0, 1, 0),r0=(0, 0, 1)的关系,这就是新坐标值的意义所在。
这也是矩阵乘法设计成这样的价值所在。
所以,把3×3矩阵M的3行看做转换后的3个基向量,那么任意一个1×3的行向量v乘以M,就得到了v转换后的坐标。这就是说,乘以该矩阵就相当于执行了一次坐标转换。若有aM=b,我们就可以说,M将a转换到b。
如何建立需要的矩阵?
上一节说明了,3×3矩阵的每一行都能解释为转换后的基向量。初始坐标系中的向量/点经过转换,得到了各自新的坐标值。那么,初始坐标系中的基向量p0=(1, 0, 0),q0=(0, 1, 0),r0=(0, 0, 1)经过转换,得到的新坐标值是?
观察这三个式子,你会发现新的基向量恰好组成了我们需要的转换矩阵。
一般情况下,我们是不能预先得到转换矩阵的。而三个式子就给出了获取转换矩阵的方法。就是说,只要我们能先用别的什么方法求出新的基向量的坐标值,就能拼出转换矩阵,然后就可以从任意一个向量/点的初始坐标值得到其新的坐标值!
总之,矩阵等价于变换后的基向量。
2D示例
比如这个矩阵:
这个矩阵代表的变换是什么?
首先,从矩阵中抽出基向量p和q:
下图展示了p0=(1, 0), q0=(0, 1)转换到p,q后的样子:
加个图片会看起来更直观:
“不幸的是,没有人能告诉您矩阵像什么——您必须自己去感受。”
《3D Math Primer for Graphics and Game Development》读书笔记1的更多相关文章
- 《Linux/Unix系统编程手册》读书笔记 目录
<Linux/Unix系统编程手册>读书笔记1 (创建于4月3日,最后更新4月7日) <Linux/Unix系统编程手册>读书笔记2 (创建于4月9日,最后更新4月10日) ...
- 《Linux/Unix系统编程手册》读书笔记9(文件属性)
<Linux/Unix系统编程手册>读书笔记 目录 在Linux里,万物皆文件.所以文件系统在Linux系统占有重要的地位.本文主要介绍的是文件的属性,只是稍微提及一下文件系统,日后如果有 ...
- 《Linux/Unix系统编程手册》读书笔记8 (文件I/O缓冲)
<Linux/Unix系统编程手册>读书笔记 目录 第13章 这章主要将了关于文件I/O的缓冲. 系统I/O调用(即内核)和C语言标准库I/O函数(即stdio函数)在对磁盘进行操作的时候 ...
- 《Linux/Unix系统编程手册》读书笔记7 (/proc文件的简介和运用)
<Linux/Unix系统编程手册>读书笔记 目录 第11章 这章主要讲了关于Linux和UNIX的系统资源的限制. 关于限制都存在一个最小值,这些最小值为<limits.h> ...
- 《Linux/Unix系统编程手册》读书笔记6
<Linux/Unix系统编程手册>读书笔记 目录 第9章 这章主要讲了一堆关于进程的ID.实际用户(组)ID.有效用户(组)ID.保存设置用户(组)ID.文件系统用户(组)ID.和辅助组 ...
- 《Linux/Unix系统编程手册》读书笔记5
<Linux/Unix系统编程手册>读书笔记 目录 第8章 本章讲了用户和组,还有记录用户的密码文件/etc/passwd,shadow密码文件/etc/shadow还有组文件/etc/g ...
- 《Linux/Unix系统编程手册》读书笔记4
<Linux/Unix系统编程手册>读书笔记 目录 第7章: 内存分配 通过增加堆的大小分配内存,通过提升program break位置的高度来分配内存. 基本学过C语言的都用过mallo ...
- 《Linux/Unix系统编程手册》读书笔记3
<Linux/Unix系统编程手册>读书笔记 目录 第6章 这章讲进程.虚拟内存和环境变量等. 进程是一个可执行程序的实例.一个程序可以创建很多进程. 进程是由内核定义的抽象实体,内核为此 ...
- 《Linux/Unix系统编程手册》读书笔记1
<Linux/Unix系统编程手册>读书笔记 目录 最近这一个月在看<Linux/Unix系统编程手册>,在学习关于Linux的系统编程.之前学习Linux的时候就打算写关于L ...
- 《Linux/Unix系统编程手册》读书笔记2
<Linux/Unix系统编程手册>读书笔记 目录 第5章: 主要介绍了文件I/O更深入的一些内容. 原子操作,将一个系统调用所要完成的所有动作作为一个不可中断的操作,一次性执行:这样可以 ...
随机推荐
- RSA密钥之C#格式与Java格式转换
前言 最近由于项目需求,服务端由c#编写,客户端由java编写.通信数据使用RSA非对称加密.但是java和c#生成的密钥格式是不一样的,所以需要转换格式才可以正常使用.网上搜到使用java进行格式转 ...
- java中的throw与throws的区别
什么时运行时异常?什么是非运行时异常? 通俗的讲: 运行时异常:就是编译通过,运行时就崩了,比如数组越界. 非运行时异常:就是编译不通过,这时就得必须去处理了.不然就没法运行了. 全面的讲: Thro ...
- Swift 获取屏幕宽高
let screenh = UIScreen.mainScreen().applicationFrame.size.heightlet screenw = UIScreen.mainScreen(). ...
- 【前端性能】高性能滚动 scroll 及页面渲染优化--转发
本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的关系,节流与防抖,pointer-events:none 优化滚动.因为本文涉及了很多很多基础,可以对照上面的知 ...
- 限制input只能输入金额(类似:100.00|100.9|100)
$(".inputmoney").keyup(function () { var reg = $(this).val().match(/\d+\.?\d{0,2}/); ...
- Lattice Codes
最近在做的一些关于lattice codes的工作,想记录下来. 首先,我认为lattice coding是一种联合编码调制技术,将消息序列映射到星座点.其中一个良好的性质是lattice point ...
- Delphi 中的自动释放策略-转
八.使用结构体而不是结构体指针: 很重要 一.指定 Owner 后, 随 Owner 连带释放: //uses Vcl.StdCtrls, Vcl.ExtCtrls; var panel: TPane ...
- 如何卸载重装docker?
http://blog.csdn.net/yangzhenping/article/details/43671843
- WebRTC通信流程
WebRTC是HTML5支持的重要特性之一,有了它,不再需要借助音视频相关的客户端,直接通过浏览器的Web页面就可以实现音视频对聊功能.而且WebRTC项目是开源的,我们可以借助WebRTC源码快速构 ...
- Thinkphp3.2.3路径书写注意
尽量不要这样写: ./public/img/a.jpg 应该这样写:__PUBLIC__/img/a.jpg 不然会引起不兼容 如首页地址 http://192.168.1.100/rjshop/时