concentrate on c/c++ related technology

plan,refactor,daily-build, self-discipline,

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  37 Posts :: 1 Stories :: 12 Comments :: 0 Trackbacks

常用链接

留言簿(9)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

基本变换

平移变换
平移矩阵= (1 0 0 0   )
          (0 1 0 0   )
          (0 0 1 0   )
          (tx ty tz 1)
点p(px,py,pz,1)与平移矩阵相乘以后,就可以得到新点p' = (px+tx,py+ty,pz+tz,1),在计算机实时图形学上面的平移矩阵好象是错误的呀,要转置以后才对的。
在书中记录的平移是:
(1 0 0 tx)
(0 1 0 ty)
(0 0 1 tz)
(0 0 0 1 )
另外平移矩阵的逆矩阵应该是:
(1 0 0 -tx)
(0 1 0 -ty)
(0 0 1 -tz)
(0 0 0  1 )
这里采用代数行列式的形式计算出来的,具体来说,就是将平移矩阵转置,获得转置矩阵pt(t),那么p-1(t) = pt(-t).
在D3D里面一般用函数D3DXMatrixTranslation.

旋转变换

绕x轴旋转
(1 0 0 0 )
(0 cosA -sinA 0)
(0 sinA cosA 0)
(0 0 0 1)
假设存在某个点p(px,py,pz,1),那么经过绕x旋转以后,就可以得到
(px,pycosA + pzsinA, pzcosA-pysinA,1)
在D3D里面一般用函数D3DXMatrixRotationX

绕y轴旋转
(cosA 0 sinA 0)
(0 1 0 0 )
(-sinA 0 cosA 0)
(0 0 0 1)
假设存在某个点p(px,py,pz,1),那么经过绕y旋转以后,就可以得到
(pxcosA-pzsinA,py,pxsinA+pzcosA,1)
在D3D里面一般用函数D3DXMatrixRotationY

绕z轴旋转
(cosA -sinA 0 0)
(sinA cosA 0 0)
(0 0 1 0)
(0 0 0 1)
假设存在某个点p(px,py,pz,1),那么经过z旋转以后,就可以得到
(pxcosA + pysinA, pycosA - pxsinA, pz, 1) 
在D3D里面一般用函数D3DXMatrixRotationZ

当然还有一个可以自定义的旋转轴做法:
D3DXMatrixRotationAxis

对绕任意旋转角度A的3x3旋转矩阵RL来说,其对角线元素之和是一个与坐标轴无关的常量,称为迹
tr(R) = 1 + 2cosA

缩放变换
缩放矩阵
s = (sx 0 0 0)
    (0  sy 0 0)
    (0  0 sz 0)
    (0  0  0  1)
假设存在某个点p(px,py,pz,1),那么经过缩放变换以后,就可以得到
(pxsx,pyxy,pzsz,1)
在齐次坐标系里面,创建一个一致性缩放矩阵的另外一种方式是通过改变(3,3)处的元素实现
比如
s = (1 0 0 0)
    (0 1 0 0)
    (0 0 1 1)
    (0 0 0 factor)
在这里这个factor将起主要作用.
如果对缩放矩阵的一个或者三个分量置为空,就会产生一个反射矩阵,或者成为镜像矩阵。如果其中两个缩放因子是-1,那么将会旋转180度

错切变换
错切变换是使图形产生一个扭变。分为x和y方向的错切变换。

    图形沿x方向的错切矩阵表示为 

     [1 0 0]
[x' y' 1] = [x y 1][b 1 0] = [ x+by y 1]
                   [0 0 1]

    此时,图形的y坐标不变,x坐标随坐标(x y)和系数b作线性变化。b>0,图形沿+x方向做错切;b<0,图形沿-x方向做错切;b≠0。

    图形沿y方向的错切矩阵表示为     

     [1 d 0]
[x' y' 1] = [x y 1][1 1 0] = [ x dx+y 1]
                   [0 0 1] 

   此时,图形的x坐标不变,y坐标随坐标(x y)和系数d作线性变化。d>0,图形沿+y方向做错切;d<0,图形沿-y方向做错切;d≠0。 
一般在游戏中被用来扭曲整个场景,从而产生某种虚幻效果,或者抖动来产生模糊反射效果。
Hxy:第一下标是由错切矩阵改变的坐标,第二个下标表示要进行错切操作的坐标。

          (1 0 s 0)
Hxz(s) =  (0 1 0 0)
          (0 0 1 0)
          (0 0 0 1)
假设存在P点(px,py,pz,1)与矩阵相乘可以得到(px + s pz, py, pz,1)
任何错切矩阵的行列式值总为1。

变换级联
矩阵乘法存在不可交换性,将多个矩阵级联为单个矩阵可以获得比较好的效率。

刚体变换
仅由平移和旋转两种级联所做成的变换称为刚体变换,这种变换具有长度和角度不变的特性。
可以将刚体矩阵X写成一个平移矩阵T(t)和一个旋转矩阵R的级联。
            ( r00 r01 r02 tx)
            ( r10 r11 r12 ty)
X = T(t)R = ( r20 r21 r22 tz)
            ( 0   0   0   1)
X的逆矩阵 = (T(t)R)的逆矩阵 = R的逆矩阵*T(t)的逆矩阵 = R的逆矩阵 * T(-t)
首先对矩阵R左上角的3x3矩阵进行转置,然后改变平移矩阵T的平移值符号,最后将这两个矩阵进行相乘即可以得到相应的逆矩阵。
另外一种求X的逆矩阵方法:
                      (r,0转置)
R = ( r,0 r,1 r,2) = (r,1转置)
                      (r,2转置)

X = ( R     t)
    ( 0转置 1)

法线变换
法线必须通过用变换集合图形的逆矩阵的转置矩阵进行变换。
在实际应用中,如果变换矩阵是正交的,就没有必要计算该矩阵的逆矩阵
在这种情况下,正交矩阵的逆矩阵就是转置矩阵,可以用这个矩阵本身对法线进行变换。

如果使用一个或者多个一致性缩放矩阵进行变换,就不需要计算相应的逆矩阵,因为这个缩放只影响变换后的法线长度,而不影响其方向,在这种情况下,一般都要在矩阵变换对法线进行变化之后,需要对法线进行归一化。

逆矩阵计算
1) 如果矩阵是单个变换或者一些给定参数的变换,那么很容易通过调换参数和矩阵顺序计算出相应的逆矩阵,比如M = T(t)R(s), 那么M的逆矩阵为R(-s)T(-t)
2) 如果矩阵是正交,那么其逆矩阵就是其转置,任何的旋转变换都是正交的。
3) 在不知道任何特殊信息的情形下,可以采用伴随矩阵,克莱姆法则,LU分解,或者高斯消去法来计算逆矩阵


欧拉变换
主要用来构造一个自定位(如相机)或者任何实体处于特定方向的矩阵。
首先,需要建立一种默认的观察方向,通常情况下,头部沿着y轴方向,面部朝向为z轴负方向。
当使用欧拉变换的时候,会出现所谓万向锁(Gimbal Lock),这种现象通常出现在旋转变换的时候出现,其中会缺少一个自由度。

改变head就是使观察者摇头说不,改变pitch就是点头,改变roll就是头向一边歪。

矩阵分解
主要应用场合:
1)提取缩放因子
2)确定特定系统所需要的变换
3)确定模型是否只经历过刚体变换
4)在动画的关键帧之间插值
5)从旋转矩阵中消除其中的错切变换

四元组
四元数是一个用来构造强制变换的有力工具,在某些情况下,要比欧拉角和欧拉矩阵更具有优势,特别是在遇到旋转和定向的情况时更是如此。
数学背景
q = (qv,qw) = iqx + jqy + kqz + qw = qv + qw
qv = iqx + jqy + kqz = (qx,qy,qz)
i*i = j*j = k*k = -1, jk = -kj = i, ki = -ik = j, ij = -ji = k
乘法:
QR = (iqx + jqy + kqz + qw)(irx + jry + krz + rw)
   = i*(qyrz - qzry + rwqz + qwrx)
     + j*(qzrx - qxrz + rwqy + qwry)
     + k*(qxry - qyrx + rwqz + qwrz)
     + qwrw - qxrx - qyry - qzrz
   = qv * rv + rwqw - qxrx - qyry - qzrz

加法:
Q + R = (qv, qw) +(rv,rw) = (qv + rv, qw + rw)

共厄:
Q = (qv,qw)共厄 = (-qv,qw)

范数:
n(Q) = qx * qx + qy * qy + qz * qz + qw * qw

同一性:
i = (0,1)

逆:
q的逆 = 1/n(Q) *Q共厄

共轭法则:

Q共轭 = Q共轭

( Q + R)共轭 = Q共轭 + R共轭

(QR)共轭 = R共轭Q共轭

范数法则:
n(Q共厄) = n(Q)

n(QR) = n(Q)n(R)

乘法定律:
  线性关系: P(sQ + tR) = sPQ + tPR
             (sP +tQ)R = sPR + tQR
  组合关系:P(QR) = (PQ)R

单位四元组Q=(qv,qw)的模n(Q)为1,基于此,Q可以表示为:
Q = (sinAuq,cosA) = sinAuq + cosA

对于一些三维向量uq来说,有||uq|| = 1,因为:
n(Q) = n(sinAuq,cosA) = sinA*sinA*(uq.uq) + cosA*cosA = 1
当且仅当uq*uq = ||uq|| *||uq||.

球面线性插值
球面线性插值是在给定两个单位四元组Q和R,以及一个参数t(0<=t<=1)的情况下计算插值四元组,
该运算的代数形式可以用下面的复合四元组S表示:
S(Q,R,t) = (RQ的逆)tQ

slerp表示球面线性插值
slerp(Q,R,t) = sinA(1-t)/sinA*Q + sinAt/sinA *R
cosA = qxrx + qyry + qzrz + qwrw
对于0<=t<=1来说,slerp函数计算是唯一的插值四元组
这些四元组构成了四维单位球面上从Q(t=0)到R(t=1)之间的最短弧。
这条弧位于一个圆上,这个圆由Q,R,以及原点组成的平面与四维单位球面相交形成的

Ai = Bi = Qi exp(-(log(QiQi-1)+log(QiQi+1))/4)

使用Qi,Ai和Bi对使用平滑三次样条的四元组进行球面插值
squad(Qi,Qi+1,Ai,Ai+1,t) = slerp(slerp(Qi,Qi+1,t),slerp(Ai,Ai+1,t),2t(1-t))

squad函数是由slerp函数重复使用球面插值而构成的,该插值通过初始化方位Qi而不是Ai,Ai主要用来表示初始方位的切线方向。

从一个向量到另外一个向量的旋转
四元组计算规则:
首先对s和t归一化,然后,计算出单位旋转轴u,具体通过式u = (s*t)/||s x t||来计算。
其次e = s.t = cos2A,||s * t|| = sin2A
其中2A表示s与t之间的夹角.
这样,从s到t旋转的四元组可以表示为Q =(sinAu,cosA).

posted on 2008-05-25 15:58 jolley 阅读(1838) 评论(1)  编辑 收藏 引用

Feedback

# re: 实时计算机图形学--图形变换 2012-04-09 19:23 Code Knight
一般书上采用的是OGL的列矩阵书写方式.  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理