我的博客和笔记我的博客和笔记
首页
文章
  • TurboLink
  • TinyEncrypt
  • UnrealStyleGuide
  • AxTrace
  • Cyclone
  • 数学相关
  • 图形学
  • 密码学
  • 编程语言
关于
GitHub
首页
文章
  • TurboLink
  • TinyEncrypt
  • UnrealStyleGuide
  • AxTrace
  • Cyclone
  • 数学相关
  • 图形学
  • 密码学
  • 编程语言
关于
GitHub
  • 我的文章

    • 从抛币协议到智能合约

      • Part1
      • Part2
    • JPEG算法解密

      • Part1
      • Part2
      • Part3
      • Part4
      • Part5
      • Github
    • SPH算法简介

      • Part1
      • Part2
      • Part3
      • Part4
      • Github
    • 赌博中的数学:Martingle策略
    • 如何生成一个随机的圆形
    • 一个简单的DH密钥协商算法的实现
    • 如何计算线段和圆的交点
    • 一道数学趣题
    • 斐波那契数列和1/89
    • 匀速贝塞尔曲线运动的实现

      • Part1
      • Part2
  • 开源项目

    • TurboLink
    • TinyEncrypt
    • UnrealStyleGuide
    • AxTrace
    • Cyclone
  • 学习笔记

    • 数学相关

      • 常用数学符号
      • 群
      • 数论(一)
      • 数论(二)
      • 数论(三)
      • 概率
    • 密码学

      • RSA
      • 抛币协议
      • 智能扑克协议
    • 图形学

      • 数学基础

        • 矢量
        • 矩阵
        • 立体角
        • 几何变换(一)
          • 1. 线性变换
            • 1.1 定义
            • 1.2 举例
            • 1.3 使用矩阵表示
          • 2. 缩放变换
            • 2.1 定义
          • 3. 旋转变换
            • 3.1 正方向约定
            • 3.2 围绕标准轴旋转
            • 3.3 围绕任意轴
            • 3.4 四元数
        • 几何变换(二)
        • 法线变换
        • 摄像机变换
      • 光照模型

        • 传统光照模型
        • 光度学
        • 双向反射分布函数(BRDF)
        • 微平面理论(一)
        • 微平面理论(二)
        • 微平面理论(三)
        • 光照方程
      • 环境光渲染

        • 环境光渲染(一)
        • 环境光渲染(二)
    • 编程语言

      • JavaScript

        • 环境搭建
        • 基本语法
        • 函数
        • 对象和类

几何变换(一)


1. 线性变换

1.1 定义

假设有某种数学函数τ,输入矢量u→,输出的仍然是一个矢量,且满足以下条件

τ(u+v)=τ(u)+τ(v)τ(ku)=kτ(u)

那么定义τ为线性变换

1.2 举例

比如τ(ux,uy,uz)=(ux2,uy2,uz2)就不是线性变换,因为不满足第二条

1.3 使用矩阵表示

一般使用矩阵表示一个线性变换,设一个三维矢量v→=[x,y,z]T=xi→+yj→+zk→,那么对其做线性变换

(1.3.1)τ(v→)=τ(xi→+yj→+zk→)=τ(i→)x+τ(j→)y+τ(k→)z=[↑↑↑τ(i→)τ(j→)τ(k→)↓↓↓][xyz]=[T11T12T13T21T22T23T31T32T33][xyz]

2. 缩放变换

2.1 定义

定义放缩变换为

S(x,y,z)=(Sxx,Syy,Szz)

用矩阵表示

S=[Sx000Sy000Sz]

3. 旋转变换

以右手坐标系为例

3.1 正方向约定

描述一个旋转角度时,一般约定沿着坐标轴负方向向原点看,逆时针为正方向

3.2 围绕标准轴旋转

3.2.1 结果

围绕x,y,z轴旋转θ的旋转矩阵

Rx=[1000cos⁡(θ)−sin⁡(θ)0sin⁡(θ)cos⁡(θ)]Ry=[cos⁡(θ)0sin⁡(θ)010−sin⁡(θ)0cos⁡(θ)]Rz=[cos⁡(θ)−sin⁡(θ)0sin⁡(θ)cos⁡(θ)0001]

3.2.2 求解过程

以Rz为例

标准矢量i→=[1,0,0]T,j→=[0,1,0]T,k→=[0,0,1]T,经过旋转θ后,结果为

Rz(i→)=[cos⁡(θ),sin⁡(θ),0]TRz(j→)=[−sin⁡(θ),cos⁡(θ),0]TRz(k→)=[0,0,1]T

所以根据公式1.3.1

Rz=[cos⁡(θ)−sin⁡(θ)0sin⁡(θ)cos⁡(θ)0001]

3.3 围绕任意轴

3.3.1 结果

有穿过原点单位轴n→

求围绕该轴旋转θ的旋转矩阵

3.3.2 求解过程

将矢量v→分解成两个矢量的和,一个是平行于n→的分量v→1和垂直于n→的分量v→2

v→=v→1+v→2∥v→1∥=∥v→∥cos⁡(α)∥v→2∥=∥v→∥sin⁡(α)

由于n→是单位矢量,∥n→∥=1,所以

(3.3.2.1)v→⋅n→=∥v→∥∥n→∥cos⁡(α)=∥v→∥cos⁡(α)=∥v→1∥(3.2.2.2)∥v→×n→∥=∥v→∥∥n→∥sin⁡(α)=∥v→∥sin⁡(α)=∥v→2∥

所以根据公式3.3.2.1,v→1和n→同方向,且长度和v→⋅n→相等,所以

(3.3.2.3)v→1=∥v→1∥n→=(v→⋅n→)n→

由于v→1不受旋转影响,所以

(3.3.2.4)Rn(v→)=v→1+Rn(v→2)

Rn(v→2)可以分解成两部分,一部分是平行于v→2的分量v→2cos⁡(θ)另一部分是垂直于v→2的分量v→2sin⁡(θ),联合公式3.2.2.2

(3.3.2.5)Rn(v→2)=v→2cos⁡(θ)+(n→×v→)sin⁡(θ)

代入3.3.2.4可以得到

(3.3.2.6)Rn(v→)=v→1+Rn(v→2)=v→1+v→2cos⁡(θ)+(n→×v→)sin⁡(θ)=v→1+(v→−v→1)cos⁡(θ)+(n→×v→)sin⁡(θ)=v→cos⁡(θ)+(1−cos⁡(θ))v→1+(n→×v→)sin⁡(θ)=v→cos⁡(θ)+(1−cos⁡(θ))(v→⋅n→)n→+(n→×v→)sin⁡(θ)

这个公式称为罗德里格旋转公式Rodrigues' rotation formula,使用以下方法得到其矩阵形式

3.3.3 一般形式

Rn(v→)=v→−v→+v→cos⁡(θ)+(1−cos⁡(θ))(v→⋅n→)n→+(n→×v→)sin⁡(θ)=v→−(1−cos⁡(θ))v→+(1−cos⁡(θ))(v→⋅n→)n→+(n→×v→)sin⁡(θ)=v→+(1−cos⁡(θ))[(v→⋅n→)n→−v→]+(n→×v→)sin⁡(θ)=v→+(1−cos⁡(θ))[(v→⋅n→)n→−(n→⋅n→)v→]+(n→×v→)sin⁡(θ)

根据矢量三重积公式,可以得到

(v→⋅n→)n→−(n→⋅n→)v→=n→×(n→×v→)

所以

Rn(v→)=v→+(1−cos⁡(θ))[n→×(n→×v→)]+(n→×v→)sin⁡(θ)

使用向量n→的叉乘矩阵[n]×来代替叉乘,这里记矩阵Mn为向量n→的叉积矩阵

Mn=[0−nznynz0−nx−nynx0]

使用矩阵形式表达罗德里格旋转公式

Rn(v→)=Iv→+(1−cos⁡(θ))[Mn(Mnv→)]+Mnv→sin⁡(θ)=[I+(1−cos⁡(θ))Mn2+Mnsin⁡(θ)]v→

所以矩阵形式的罗德里格旋转公式的公式为

Rn=I+Mn2(1−cos⁡(θ))+Mnsin⁡(θ)

3.3.4 三维行列式

设n→=[x,y,z]T,c=cos⁡(θ),s=sin⁡(θ)分别将i→,j→,k→带入3.3.2.6,得到

Rn(i→)=ci→+(1−c)(i→⋅n→)n→+(n→×i→)s=[c+(1−c)x2,(1−c)xy+sz,(1−c)xz−sy]TRn(j→)=[(1−c)xy−sz,c+(1−c)y2,(1−c)yz+sx]TRn(k→)=[(1−c)xz+sy,(1−c)yz−sx,c+(1−c)z2]T

代入公式1.3.1得到

Rn=[c+(1−c)x2(1−c)xy−sz(1−c)xz+sy(1−c)xy+szc+(1−c)y2(1−c)yz−sx(1−c)xz−sy(1−c)yz+sxc+(1−c)z2]

3.4 四元数

3.4.1 复数

复数(Complex Number)可以表达为

z=a+bia,b∈R,i2=−1

其中a被成为实部(Real Part), b被称为虚部(Imaginary Part), 复数的基本运算规律如下,设z1=a1+b1i,z2=a2+b2i,那么

z1+z2=(a1+a2)+(b1+b2)iz1−z2=(a1−a2)+(b1−b2)iz1z2=(a1a2−b1b2)+(a1b2+a2b1)i

3.4.2 四元数定义

四元数(Quaternion)可以视为对复数的扩充,有1个实部,3个虚部,形式如下

q=s+xi+yj+zk

其中s,x,y,z∈R,i,j,k满足如下计算性质

i2=j2=k2=ijk=−1ij=kji=−kjk=ikj=−iki=jik=−j

汇总到如下表格中

ijk
i−1k−j
j−k−1i
kj−i−1

四元数也可以表达成将实数部和虚数部分开的形式,对于四元数q=s+xi+yj+zk,设v→=[x,y,z]T,则这个四元数可以表达为

q=[s,v→]

3.4.3 四元数的基本运算

对于两个四元数q1=[s1,v1→],q2=[s2,v2→],基本运算规律如下

q1+q2=[s1+s2,v1→+v2→]q1−q2=[s1−s2,v1→−v2→]q1q2=[s1s2−v1→⋅v2→,s1v2→+s2v1→+v1→×v2→]

四元数的乘法满足结合律,但不满足交换律

(q1q2)q3=q1(q2q3)q1q2≠q2q1

但如果q1,q2中的向量部分平行,由于v1→×v2→=0,易证

(3.4.3.1)q1q2=q2q1(whenv1→∥v2→)

定义四元数q=s+xi+yj+zk的模为

∥q∥=s2+x2+y2+z2

如果一个四元数的模为1,那么称这个四元数为单位四元数

3.4.4 四元数的共轭和逆

定义四元数q=[s,v→]的共轭四元数q―为

q―=[s,−v→]

共轭四元数满足如下运算

(3.4.4.1)qq―=q―q=∥q∥2

对于单位四元数,有qq―=1
定义四元数q的逆为q−1,满足qq−1=1,由公式3.4.4.1可知

qq−1=1=qq―∥q∥

所以

(3.4.4.2)q−1=q―∥q∥2

四元数的逆满足如下运算

(3.4.4.3)(q1q2)−1=q2−1q1−1(q1q2…qn)−1=qn−1…q2−1q1−1

易知,如果是单位四元数

(3.4.4.4)q1q2…qn―=qn―…q2―q1―

3.4.5 四元数与向量

如果一个四元数的实部为0,那么称之为纯四元数(Pure Quaternion),由于纯四元数仅有3个虚部,可以将一个3D向量转换为一个纯四元数。记qv=[0,v→],那么

λqv=[0,λv→]qu±qv=[0,u→±v→]

由此可见,向量的线性运算,都可以使用与之对应的纯四元数来代替。但乘法则不同,设两个纯四元数qu=[0,u→],qv=[0,v→],相乘后结果为

(3.4.5.1)quqv=[−u→⋅v→,u→×v→]

对于向量v→,记四元数q(θ,v→)=[cos⁡θ,v→sin⁡θ],这种四元数有一些很有用的特性,首先如果v→是单位向量,那么q(θ,v→)是单位四元数,易证:

∥q(θ,v→)∥=cos2⁡θ+sin2⁡θ(vx2+vy2+vz2)=1

另外

(3.4.5.2)q(α,v→)q(θ,v→)=[cos⁡α,v→sin⁡α][cos⁡θ,v→sin⁡θ]=[cos⁡αcos⁡θ−sin⁡αsin⁡θ,v→(cos⁡αsin⁡θ+cos⁡θsin⁡α)]=[cos⁡(α+θ),v→sin⁡(α+θ)]=q(α+θ,v→)q(θ,v→)2=q(2θ,v→)

3.4.6 使用四元数表达旋转

观察上面推导罗德里格旋转公式过程中的公式3.3.2.5,其中

n→×v→=n→×(v1+v2)=n→×v1→+n→×v2→=n→×v2→

带入公式3.3.2.5,可以得到

(3.4.6.1)Rn(v→2)=v→2cos⁡(θ)+(n→×v2→)sin⁡(θ)

设两个纯四元数qn,qv2

(3.4.6.2)qn=[0,n→]qv2=[0,v2→]

根据公式3.4.5.1

(3.4.6.3)qnqv2=[−n→⋅v2→,n→×v2→]=[0,n→×v2→]

所以qnqv2是一个纯四元数
由于3.4.6.1中都是线性计算,将3.4.6.2和3.4.6.3代入其中,可以得到Rn(v→2)的四元数形式

(3.4.6.4)[0,Rn(v→2)]=qv2cos⁡θ+qnqv2sin⁡θ=(cos⁡θ+qnsin⁡θ)qv2=[cos⁡θ,n→sin⁡θ]qv2=q(θ,n→)qv2

设一个新的四元数p

(3.4.6.5)p=q(θ2,n→)=[cos⁡θ2,n→sin⁡θ2]

根据公式3.4.5.2,可以得到

pp=q(θ,n→)

且由于p是单位四元数,可以知道

pp−1=pp―=1

将3.4.6.4带入3.3.2.4中,可以得到罗德里格旋转公式的四元数形式为

(3.4.6.6)Rn(v→)=v→1+Rn(v→2)[0,Rn(v→)]=qv1+q(θ,n→)qv2=pp―qv1+ppqv2

由于n→∥v1→,根据公式3.4.3.1,可知p―qv1=qv1p―
由于n→⊥v2→,可以推断出pqv2=qv2p―,证明如下:

pqv2=[cos⁡θ2,n→sin⁡θ2][0,v2→]=[0,v2→cos⁡θ2+(n→×v2→)sin⁡θ2]qv2p―=[0,v2→][cos⁡θ2,−n→sin⁡θ2]=[0,v2→cos⁡θ2−(v2→×n→)sin⁡θ2]

带入3.4.6.6,可以得到

(3.4.6.7)[0,Rn(v→)]=pqv1p―+pqv2p―=p(qv1+qv2)p―=pqvp―

也就是说,对于向量v→,围绕单位向量n→旋转θ,只需要构造四元数[cos⁡θ2,n→sin⁡θ2],可以利用下面的等式计算旋转后的向量v′→

[0,v′→]=[cos⁡θ2,n→sin⁡θ2][0,v→][cos⁡θ2,−n→sin⁡θ2]

3.4.7 四元数组合

使用四元数表达旋转有一个好处就是可以实现组合、插值等计算,例如一个向量v经过两次旋转变化,用四元数表示分别是q1,q2,那么

q′=q2(q1qvq1―)q2―=(q2q1)qv(q1―q2―)

根据公式3.4.4.4,可知

q′=(q2q1)qv(q2q1―)

3.4.7 四元数转换为旋转矩阵

两个四元数相乘,可以转换为同等效果的矩阵,设两个四元数

p=a+bi+cj+dkq=s+xi+yj+zk

那么

pq=(a+bi+cj+dk)(s+xi+yj+zk)=(as−bx−cy−dz)+(bs+ax−dy+cz)i+(cs+dx+ay−bz)j+(ds−cx+by+az)k

可以将左乘四元数p视作左乘矩阵L(p)

L(p)=[a−b−c−dba−dccda−bd−cba]

而右乘四元数p视作左乘矩阵R(q)

Q(q)=[a−b−c−dbad−cc−dabdc−ba]

那么旋转一个向量v→对应的四元数qv的过程可以写作

pqvp―=L(p)R(p―)qv

或者

pqvp―=R(p―)L(p)qv

容易证明,这两个结果是一样的,经计算

L(p)R(p―)qv=[a−b−c−dba−dccda−bd−cba][abcd−ba−dc−cda−b−d−cba][0vxvyvz]=[100001−2c2−2d22bc−2ad2ac+2bd02bc+2ad1−2b2−2d22cd−2ab02bd−2ac2ab+2cd1−2b2−2c2][0vxvyvz]

忽略掉四元数中为0的实数部分,可以将一个旋转四元数转换为旋转矩阵

v′=[1−2c2−2d22bc−2ad2ac+2bd2bc+2ad1−2b2−2d22cd−2ab2bd−2ac2ab+2cd1−2b2−2c2][vxvyvz]

其中

a=cos⁡(θ/2)b=sin⁡(θ/2)nxc=sin⁡(θ/2)nyd=sin⁡(θ/2)nz
Prev
立体角
Next
几何变换(二)