为了对一个点进行变换(平移、伸缩、旋转等),可以用一个4  ×  4 的的变换矩阵来表示,如最常见的是使用一个模型视图变换矩阵,来变换点、线、多边形以及其它几何体,也可以变换多边形表面的切向量。变换思路如下:设置一个4  ×  4 的矩阵中元素的值,使其表示某一具体的变换。然后将某一点的坐标或者某一向量的分量放入一个1  ×  4 的行向量 v 中。乘积 vX 就生成了经过变换的向量 v˜ ,例如,如果 X 表示沿着 x 轴平移10个单位, v=[2,6,−3,1] ,则乘积 vX=v˜=[12,6,−3,1] 。

前面提到了将某一点的坐标或者某一分量的各分量放入一个1  ×  4的行向量 v 中。但是在几何学中,表示3D空间中的某点信息是使用3个分量(XYZ)来表示的!为了使向量-矩阵相乘有意义,我们必须将3D的点或向量拓展为4D行向量。

如何使用第四个分量?这个分量我们用w表示,其中w叫做齐次坐标。取值为0或者1。当W分量为1时,是为了保证点的平移变换能正确进行。而对于向量,没有必要进行平移变换,而将W分量设为0是为了防止对向量实施平移变换。

PS:

拓展后的4D向量被称为齐次向量,因此齐次向量即可以表示点,也可以表示向量,所以注意本文提到的名词“向量时,注意区分我指的是点还是向量,一般来说,下文提到的”向量“时,基本上指代的是点。

有时,我们所定义的矩阵改变了一个向量的分量w的值(即 w≠0  且 w≠1 )如下所示:

P=[p1,p2,p3,1]⎡⎣⎢⎢1000010000100010⎤⎦⎥⎥=[p1,p2,p3,p3]=P′ 对于 p3≠0 和 p3≠1 的情况

可见, w=p3 。当 w≠0 且 w≠1 时,就称该变量处于齐次空间中,以区别3D空间。将齐次空间的向量映射回3D空间的方法是:用w分量去除该齐次向量的每一个分量。例如将齐次空间的向量 (x,y,z,w) 映射回3D向量x的方法如下:

[xwywzwww]=[xwywzw1]=[xwywzw]=X

在进行3D编程是,如果涉及到透视投影,则经常需要将向量由齐次空间映射到3D空间。该操作发生在顶点变换步骤的透视除法环节。在OpenGL中,一个典型的顶点变换步骤如下:

可见,对顶点的变换都是通过矩阵来完成的,下面讨论模型视图矩阵的具体形式。

平移矩阵

要想将向量(x,y,z,1)沿着 x 轴平移 px 个单位,沿着 y 轴平移 py 个单位,沿着 z 平移 pz 个单位,只需要将该向量与如下矩阵相乘:

T(p)=⎡⎣⎢⎢⎢100px010py001pz0001⎤⎦⎥⎥⎥

该平移矩阵的逆矩阵可以简单地对平移向量p取负得到。

T−1=T(p)=⎡⎣⎢⎢⎢100−px010−py001−pz0001⎤⎦⎥⎥⎥

旋转矩阵

我们可以用如下3个矩阵将一个向量分别绕着x,y,z轴旋转 θ 弧度。当沿着旋转轴指向原点的方向观察时,角度是按顺时针方向度量的。

X(θ)=⎡⎣⎢⎢10000cosθ−sinθ00sinθcosθ00001⎤⎦⎥⎥
Y(θ)=⎡⎣⎢⎢cosθ0sinθ00100−sinθ0cosθ00001⎤⎦⎥⎥
Z(θ)=⎡⎣⎢⎢cosθ−sinθ00sinθcosθ0000100001⎤⎦⎥⎥

旋转矩阵R的逆矩阵与其转置相等,即 RT=R−1 。俱备这样特点的矩阵称为正交矩阵。

比例变换矩阵

如果想让一个向量沿着x、y、z轴分别放大 qx 、 qy 、 qz 倍,可令该向量与如下矩阵相乘:

S(p)=⎡⎣⎢⎢⎢qx0000qy0000qz00001⎤⎦⎥⎥⎥

如果将比例矩阵的各个缩放因子取倒数,就得到该矩阵的逆矩阵。

S−1=S(1qx,1qy,1qz)=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢1qx00001qy00001qz00001⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥

几何变换的组合

经常需要对向量实施一系列的变换。例如我们可能先对向量进行缩放,然后在进行旋转,最后平移到所期望的位置。

这个过程的每一步都是通过让向量乘以一个矩阵来实现,矩阵的一个最关键的优点是,可以借助矩阵乘法将几种变换组合到一个变换矩阵。

例如,当我们先对向量p实施比例变换,乘以比例变换矩阵S;在对变换后的向量实施旋转变换,乘以旋转变换矩阵R:最后对变量实施平移变换,乘以平移变换矩阵T,最后得到向量 p′′′ :

pSp′Ryp′′T===p′p′′p′′′

我们可以向全部的变换组合为一种变换,然后应用该变换,得到向量 p˜ :

SRyTpQ==Qp˜

则可以验证: p′′′=p˜

法线的变换矩阵

在着色器中执行光照计算时,不仅需要我们指定顶点坐标,还需要我们去指定法线向量。对于顶点坐标,在着色器中对其施加模型视图变换和投影变换即可得到变换后的顶点坐标,但是对于法向量的变换矩阵却与顶点的变换矩阵不一样!

这是因为法线向量会随着我们的平移和旋转发生变化。比如说,如果我们忽略旋转并且假设做了一个(0,0,-5)的平移,那么法线向量(0,0,1)就会变成(0,0,-4),这不仅长度不对而且根本就指向了错误的方向!这里也许我们可以将法线向量的w分量设为0,这样就可以忽略掉那些移位变换。但是不幸的是,当模型视图矩阵包含不同的空间变换时,尤其是缩放和扭曲时,它将不再有用。比如说,如果模型视图矩阵将我们要绘制的物体放到两倍大小,那法线向量也会被拉伸,即使我们将w分量设为0。这会导致严重的光照错误。

在OpenGL中计算法线向量的变换矩阵的方法是:先求出模型视图矩阵的逆矩阵,然后再对求出的逆矩阵转置。这样就可以得到正确的变换矩阵。这样可以去掉矩阵中非正交的因素。

证明方法如下:

假设世界坐标系(未变换前)中的某条切线向量是T,法线向量是N。那么由他们是垂直的可得到: TT⋅N=0

假设他们变换到视图坐标系中后分别是 T′ 和 N′ 。那么他们应该仍然是相互垂直的: T′T⋅N′=0

假设切线向量和法线的变换矩阵为M、G。则有: (M⋅T)T⋅(G⋅N)=0

进一步推出: TT⋅MT⋅G⋅N=0

由于 TT⋅N=0 ,因此我们猜想 MT⋅G=0 .因此:

G=(M−1)T

即:应用于法线向量的变换矩阵是顶点变换矩阵的逆转置矩阵。

注意,在上面求证法线的变换矩阵的时候,是讨论OpenGL中的情况,在OpenGL中,对某一顶点实施变换时,是通过一个矩阵乘以顶点实现的,即 M⋅v=v′ ,其中,M是变换矩阵,v和 v′ 分别是变换前后的顶点。所以对于上面的证明过程有 M⋅T=T′ 而不是 T⋅M=T′ .

由于刚才提到的原因,所以在使用OpenGL编程时,我们用代码制定了一系列变换,但是最后指定的变换会最先应用到顶点上。

考虑下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N);
glMultMatrixf(M);
glMultMatrixf(L);
glBegin(GL_POINTS);
glVertex3f(v);
glEnd();

经过变换之后的顶点是 N⋅M⋅L⋅v ,也就是说,v首先与L相乘, L⋅v 的结果再与M相乘, M⋅L⋅v 再与N相乘,顶点v的变换是按照相反的顺序发生。

**********************************

参考:

《DirectX 9.0 3D游戏开发编程基础》

《OpenGL编程指南 第七版》

OpenGL法线变换详解

3D变换中法向量变换矩阵的推导

几何变换详解[转]

2012-10-23 10:59:44|  分类: 图形学|举报|字号 订阅

在三维图形学中,几何变换大致分为三种,平移变换(Translation),缩放变换(Scaling),旋转变换(Rotation)。以下讨论皆针对DirectX,所以使用左手坐标系。

平移变换

将三维空间中的一个点[x, y, z, 1]移动到另外一个点[x', y', z', 1],三个坐标轴的移动分量分别为dx=Tx, dy=Ty, dz=Tz, 即

x' = x + Tx

y' = y + Ty

z' = z + Tz

平移变换的矩阵如下。

缩放变换

将模型放大或者缩小,本质也是对模型上每个顶点进行放大和缩小(顶点坐标值变大或变小),假设变换前的点是[x, y, z, 1],变换后的点是[x', y', z', 1],那么

x' = x * Sx

y' = y * Sy

z' = z * Sz

缩放变换的矩阵如下。

旋转变换

这是三种变换中最复杂的变换,这里只讨论最简单的情况,绕坐标轴旋转,关于绕任意轴旋转,在后续的随笔中介绍。

绕X轴旋转

绕X轴旋转时,顶点的x坐标不发生变化,y坐标和z坐标绕X轴旋转θ度,旋转的正方向为顺时针方向(沿着旋转轴负方向向原点看)。[x, y, z, 1]表示变换前的点,[x', y', z', 1]表示变换后的点。变换矩阵如下。

关于旋转的正方向,OpenGL与多数图形学书籍规定旋转正方向为逆时针方向(沿着坐标轴负方向向原点看),比如Computer Graphics C Version,p409。

绕Y轴旋转

绕Y轴旋转时,顶点的y坐标不发生变化,x坐标和z坐标绕Y轴旋转θ度。[x, y, z, 1]表示变换前的点,[x', y', z', 1]表示变换后的点。变换矩阵如下。

绕Z轴旋转

绕Z轴旋转时,顶点的z坐标不发生变化,x坐标和y坐标绕Z轴旋转θ度。[x, y, z, 1]表示变换前的点,[x', y', z', 1]表示变换后的点。变换矩阵如下。

绕坐标轴旋转的矩阵推导

上面三个旋转矩阵是如何得来的呢?我们推导一下,首先看一下二维的情况,再扩展到三维即可。实际上上面三种绕坐标轴旋转的情况属于特殊的二维旋转,比如绕Z轴旋转,相当于在与XOY平面上绕原点做二维旋转。

假设点P(x, y)是平面直角坐标系内一点,其到原点的距离为r,其与X轴的夹角为A,现将点P绕原点旋转θ度,得到点P'(x', y'),P'与X轴的夹角为B,则A = B - θ。(注意,在二维坐标中,逆时针旋转时角度为正,顺时针旋转时角度为负,下图中由P旋转到P',角度为θ,若是由P'转到P,则角度为-θ)。

于是可得下面的转换方程

(式一)

写成矩阵的形式就是

求得旋转矩阵为

由于这里使用齐次坐标,所以还需加上一维,最终变成

和前面给出的绕Z轴旋转矩阵完全吻合。

对于绕X轴旋转的情况,我们只需将式一中的x用y替换,y用z替换,z用x替换即可。替换后得到

(式二)

对应的旋转矩阵为

对于绕Y轴旋转的情况,只需对式二做一次同样的替换即可,的到的变换方程为

对应的变换矩阵为

== Happy Coding ==

坐标变换 及矩阵变换相关推荐

  1. OpenGL中的坐标变换、矩阵变换

    OpenGL中六种常见坐标系: 1. Object or model coordinates(模型坐标系) 2. World coordinates(世界坐标系) 3. Eye (or Camera) ...

  2. 最本质的相机内参intrinsics与外参extrinsics分析,从建模,推导到求解

    相机内参与外参分析,从建模,推导到求解:Camera Extrinsics and Intrinsics. I. 坐标系的建立,Coordinate System. II. 转换关系,Transfor ...

  3. HTML5原生WebGL开发系列教程

    1. OpenGL中的坐标变换.矩阵变换 2. OpenGL ES 2.0编程基础 3. 原生WebGL简单Demo 4. 在WebGL中使用drawElements绘图 5. WebGL不同几何图形 ...

  4. 深度学习(20):nerf论文翻译与学习

    目录 1 Introduction 2 Related Work 3 Neural Radiance Field Scene Representation 4 Volume Rendering wit ...

  5. unity-shader相关

    title: unity-shader相关 categories: Unity3d-Shader tags: [unity, shader] date: 2017-09-12 10:05:18 com ...

  6. 机器视觉基础(2)---坐标与矩阵变换

    坐标与矩阵变换时矩阵论的基础,也是机器人,机器视觉技术的基础.这本加州理工的教材沿用了机器人技术中的表达方式.这里记录一下 ps:MIT Ocw课程<线性代数>真的非常非常有用,原本一知半 ...

  7. 【转】矩阵变换坐标系 深入理解

    转自:矩阵变换坐标系 深入理解 - 知乎 网址链接:从坐标系图中理解"空间变换" 小谈矩阵和坐标变换 矩阵坐标系变化理解 让我们从一个实际的例子入手:下图是一个用两维的笛卡尔坐标系 ...

  8. 三维坐标 偏转_三维坐标变换原理-平移, 旋转, 缩放

    给定一个二维点(x, y),那么形如(kx, ky, k)的所有三元组就都是等价的,它们就是这个点的齐次坐标(homogeneous).齐次坐标就是将一个原本是n维的向量用一个n+1维向量来表示,是指 ...

  9. WebGL矩阵变换总结(模型矩阵,视图矩阵,投影矩阵)

    矩阵变换总结(模型矩阵,视图矩阵,投影矩阵) 最近在开发项目的时候,常常用到Three.js,用起来很方便.可是,当引擎迭代升级的时候,以前的很多的技巧,并不一定使用最新的引擎.我认为应当对底层的原生 ...

最新文章

  1. 如何使用Leangoo进行简单的BUG管理
  2. 在html中使用thymeleaf编写通用模块
  3. java一次查询900w数据_一次SQL查询优化原理分析(900W+数据,从17s到300ms)
  4. github使用个人总结
  5. 一级建造师考试通过了 !
  6. opencv学习笔记7:图像加法与图像融合
  7. 在local模式下的spark程序打包到集群上运行
  8. python画画bup_Python中的高效Vector / Point类
  9. 【Flink】Flink 1.9 升级 到 flink 1.12.4 报错 flink.client.cli.AbstractCustomCommandLine <init>
  10. 操作系统(5) 并发控制(1)线程的互斥
  11. Cordova用插件时注意事项,不然,插件调用不到!
  12. java实现redis客户端_Java实现Redis客户端
  13. vue-aliplayer 阿里云播放器适配 vue
  14. Java线程状态RUNNABLE详解
  15. 快递电子面单打印接口对接demo-JAVA
  16. Java悲观锁Pessimistic-Lock常用实现场景
  17. lineageos breakfast_安卓手机刷lineageOS后电信卡不能通话解决办法
  18. 面向数据机密性的云计算脆弱性分析框架
  19. 越睡越累,原因竟然是这个!
  20. 使用iperf工具,用java的swing,编写网络带宽监测小工具

热门文章

  1. 如何通俗地理解合同矩阵
  2. 如何在Proteus8.9中从官网中添加没有的元器件(以添加STM32F103ZET6为例子)
  3. JavaWeb概述 [JavaWeb]
  4. oracle在线重定义(一)
  5. 【云代码】ip代理手机路由器对游戏行业的作用
  6. C语言初学者|新手入门
  7. 谈谈数据库里的时间戳
  8. 全选反选最快的实现方法
  9. PDN连接与默认 APN
  10. 在Ubuntu部署gitblit步骤