`
icheng
  • 浏览: 829248 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
文章分类
社区版块
存档分类
最新评论

3D 图形编程的数学基础(3) 矩阵基本变换

 
阅读更多

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

这里开始,是真正的与3D图形编程相关的知识了,前两节只能算是纯数学。

平移矩阵

要想将向量(x, y, z, 1)沿x轴平移yyyy_html_1d45df16个单位,沿y轴平移yyyy_html_m6cec65e6,沿z轴平移yyyy_html_m63b4a2d4个单位,我们只需要将该向量与如下矩阵相乘。

N(p) = yyyy_html_m1964a5f8[4]

从中可以看出4*4矩阵N中的N41,N42,N43分别控制其在x轴y轴z轴上的平移单位.

yyyy_html_m75c5e44f是单位矩阵,我们已经知道,乘以其他矩阵相当于没有乘的家伙。这个矩阵就是从单位矩阵稍微变下型,多了第4行的几个值。我们先来看yyyy_html_1d45df16为最后结果做出的贡献,向量M(x,y,z,1)与矩阵N(p)相乘后,最后X坐标的值(也就是矩阵M11的值)为x*1 + y*0 + z*0 + 1*px = x + px。(套一下矩形相乘的公式)

y,z的公式一样,就不多说了。这里可以看到,对于实施矩阵平移计算来说,需要将原向量(3维)扩充的一维(一般用w表示)设为1,不然的话,上述x坐标=x*1 + y*0 + z*0 + 0*px=x,也就是说,完全不会改变原矩阵了。

GNU Octave(matlab) 验证一下:

> p = [1,0,0,0;0,1,0,0;0,0,1,0;2,3,4,1]
p =

   1   0   0   0
   0   1   0   0
   0   0   1   0
   2   3   4   1

octave-3.2.3.exe:6:d:/Octave/3.2.3_gcc-
> x
x =

   1   2   3   1

octave-3.2.3.exe:7:d:/Octave/3.2.3_gcc-
> x * p
ans =

   3   5   7   1

octave-3.2.3.exe:8:d:/Octave/3.2.3_gcc-

x = 2 + 1 = 3,依次类推,结果正确。

在irrlicht中,平移矩阵的代码直接偷懒。。。。。利用了上述公式的推导结果,转换后的x值为x+px。。。。汗-_-!,理论和实际果然还是有差距的。不过想想,说来也是,一个加法就可以完成的平移,为啥非要整个矩阵乘法去完成?此公式的存在就让人郁闷。。。难道仅仅是因为需要的是用矩阵进行的计算。。。。。。

template <class T>
inline void CMatrix4<T>::translateVect( vector3df& vect ) const
{
    vect.X = vect.X+M[12];
    vect.Y = vect.Y+M[13];
    vect.Z = vect.Z+M[14];
}

D3D中利用函数:

// Build a matrix which translates by (x, y, z)
D3DXMATRIX* WINAPI D3DXMatrixTranslation
    ( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z );

实现矩阵的平移,具体方式不明。

缩放矩阵

我们将一单位矩阵沿X轴缩放X倍,Y轴缩放Y倍,Z轴缩放Z倍,可令该向量与下列矩阵相乘。

html_html_m2794d7de

按公式推导:X(M11)坐标值为X*x+y*0+z*0+0*0=X*x

y,z的推导类似。

GNU Octave(matlab):

> x = [1,2,3,0]
x =

   1   2   3   0

octave-3.2.3.exe:6:f:
> p
p =

   2   0   0   0
   0   3   0   0
   0   0   4   0
   0   0   0   1

octave-3.2.3.exe:7:f:
> x * p
ans =

    2    6   12    0

结果正确。其实看了实现的源代码后也会发现这种公式还是没事找事,事实上直接乘多省事啊。

irrlicht中利用下面的实现来构造一个缩放矩阵:

    template <class T>
    inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
    {
        M[0] = scale.X;
        M[5] = scale.Y;
        M[10] = scale.Z;
#if defined ( USE_MATRIX_TEST )
        definitelyIdentityMatrix=false;
#endif
        return *this;
    }

D3D中利用下面的实现完成缩放运算,直接乘就好了。。。。。。

D3DXINLINE D3DXVECTOR3* D3DXVec3Scale
    ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, FLOAT s)
{
#ifdef D3DX_DEBUG
    if(!pOut || !pV)
        return NULL;
#endif

    pOut->x = pV->x * s;
    pOut->y = pV->y * s;
    pOut->z = pV->z * s;
    return pOut;
}

旋转矩阵:

旋转矩阵是在乘以一个向量的时候有改变向量的方向但不改变大小的效果的矩阵。旋转矩阵不包括反演,它可以把右手坐标系改变成左手坐标系或反之。所有旋转加上反演形成了正交矩阵的集合。需要注意的是,进行旋转变换时,扩充3维向量的办法是令w=0;

我们可用如下3个矩阵将一个分量分别绕着x,y,z轴顺时针旋转θ弧度。

X(θ) = yyyy_html_m5a3e8644

Y(θ) = yyyy_html_6d8ae198

Z(θ) = html_html_3de18d4c

还是先看第一个公式,向量M(x,y,z,0)与矩阵X(θ)相乘后,最后X(M11)坐标值为x*1+y*0+z*0+0*0=x,Y(M12)坐标值为x*0+y*cosθ+z*(-sinθ)+0*0 = y*cosθ + z * (-sinθ),Z(M13)坐标值为x*0+y*sinθ+z*cosθ+0*0 = y*sinθ + z*cosθ,w(m14)坐标为x*0+y*0+z*0+0*1 = 0。

这个就复杂了。。。。。不太好直观的看到验证的结果,我们将其收到2维去看结果。

我们利用GNU Octave(matlab) 的compass命令在2维空间中直观的显示出向量x = [ 1, tan(pi/3), 0, 0](实际显示在x,y平面中)

我们用其围绕Z轴顺时针旋转30度时,方式是乘以θ为30的如上矩阵,结果如下:

image

> a = pi / 6
> p = [cos(a),sin(a),0,0;-sin(a),cos(a),0,0;0,0,1,0;0,0,0,1]
p =

   0.86603   0.50000   0.00000   0.00000
  -0.50000   0.86603   0.00000   0.00000
   0.00000   0.00000   1.00000   0.00000
   0.00000   0.00000   0.00000   1.00000

octave-3.2.3.exe:26:f:/Octave/3.2.3_gcc-4.4.0/bin
> x = [1, tan(pi/3), 0, 0]
x =

   1.00000   1.73205   0.00000   0.00000

octave-3.2.3.exe:27:f:/Octave/3.2.3_gcc-4.4.0/bin
> x2 = x * p
x2 =

   0.00000   2.00000   0.00000   0.00000

octave-3.2.3.exe:28:f:/Octave/3.2.3_gcc-4.4.0/bin
>

精确的30度。

irrlicht中设置旋转矩阵就有学问了:

    template <class T>
    inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
    {
        const f64 cr = cos( rotation.X );
        const f64 sr = sin( rotation.X );
        const f64 cp = cos( rotation.Y );
        const f64 sp = sin( rotation.Y );
        const f64 cy = cos( rotation.Z );
        const f64 sy = sin( rotation.Z );

        M[0] = (T)( cp*cy );
        M[1] = (T)( cp*sy );
        M[2] = (T)( -sp );

        const f64 srsp = sr*sp;
        const f64 crsp = cr*sp;

        M[4] = (T)( srsp*cy-cr*sy );
        M[5] = (T)( srsp*sy+cr*cy );
        M[6] = (T)( sr*cp );

        M[8] = (T)( crsp*cy+sr*sy );
        M[9] = (T)( crsp*sy-sr*cy );
        M[10] = (T)( cr*cp );
#if defined ( USE_MATRIX_TEST )
        definitelyIdentityMatrix=false;
#endif
        return *this;
    }

为了解释这个函数的作用,看看下列程序:

#include "irrlicht.h"
#include <math.h>

#pragma comment(lib, "Irrlicht.lib")

using namespace irr;
using namespace irr::core;

int _tmain(int argc, _TCHAR* argv[])
{

    f32 a = 30;
    f32 M[16] = { 1, 0, 0, 0, 
                  0, 1, 0, 0,
                  0, 0, 1, 0,
                  0, 0, 0, 1};
    matrix4 mt;
    mt.setM(M);

    vector3df vec(0.0, 0.0, PI / 6);

    mt.setRotationRadians(vec);

    for(int i = 0; i < 4; ++i)
    {
        for(int j = 0; j < 4; ++j)
        {
            printf("%.6f/t", mt(i, j));
        }
        printf("/n");
    }


    return 0;
}

运行结果为:

0.866025        0.500000        -0.000000       0.000000
-0.500000       0.866025        0.000000        0.000000
0.000000        0.000000        1.000000        0.000000
0.000000        0.000000        0.000000        1.000000

看到是啥了吗?没错,就是GNU Octave(matlab) 那个例子中的矩阵:

p = [cos(a),sin(a),0,0;-sin(a),cos(a),0,0;0,0,1,0;0,0,0,1]

事实上,上面程序中的vec表示不绕x,y轴旋转,绕Z轴旋转PI/6,实际的作用就是构造了上述的矩阵P。

上述矩阵通过以下成员函数应用以使用生成的矩阵,其实就是乘法-_-!

template <class T>
inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
{
    vector3df tmp = vect;
    vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
    vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
    vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
}

//! An alternate transform vector method, writing into a second vector
template <class T>
inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
{
    out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
    out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
    out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
}

//! An alternate transform vector method, writing into an array of 3 floats
template <class T>
inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
{
    out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
    out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
    out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
}

上面程序后加上如下几句,使用上面刚生成的矩阵:

vector3df x(1.0, tan(PI/3), 0.0);
mt.rotateVect(x);

printf("x = [%f, %f, %f]/n", x.X, x.Y, x.Z);

输出结果:

x = [-0.000000, 2.000000, 0.000000]

与通过GNU Octave(matlab) 的一样,精确的30度旋转。

与旋转有关的还有vector的几个函数:

//! Rotates the vector by a specified number of degrees around the Y axis and the specified center.
/** /param degrees Number of degrees to rotate around the Y axis.
/param center The center of the rotation. */
void rotateXZBy(f64 degrees, const vector3d<T>& center=vector3d<T>())
{
    degrees *= DEGTORAD64;
    f64 cs = cos(degrees);
    f64 sn = sin(degrees);
    X -= center.X;
    Z -= center.Z;
    set((T)(X*cs - Z*sn), Y, (T)(X*sn + Z*cs));
    X += center.X;
    Z += center.Z;
}

//! Rotates the vector by a specified number of degrees around the Z axis and the specified center.
/** /param degrees: Number of degrees to rotate around the Z axis.
/param center: The center of the rotation. */
void rotateXYBy(f64 degrees, const vector3d<T>& center=vector3d<T>())
{
    degrees *= DEGTORAD64;
    f64 cs = cos(degrees);
    f64 sn = sin(degrees);
    X -= center.X;
    Y -= center.Y;
    set((T)(X*cs - Y*sn), (T)(X*sn + Y*cs), Z);
    X += center.X;
    Y += center.Y;
}

//! Rotates the vector by a specified number of degrees around the X axis and the specified center.
/** /param degrees: Number of degrees to rotate around the X axis.
/param center: The center of the rotation. */
void rotateYZBy(f64 degrees, const vector3d<T>& center=vector3d<T>())
{
    degrees *= DEGTORAD64;
    f64 cs = cos(degrees);
    f64 sn = sin(degrees);
    Z -= center.Z;
    Y -= center.Y;
    set(X, (T)(Y*cs - Z*sn), (T)(Y*sn + Z*cs));
    Z += center.Z;
    Y += center.Y;
}

事实上这些函数就是前面两步的一步实现,实际就是利用了上述公式推导最后的结果,可以去对比一下。

比如下列代码:

vector3df x(1.0, tan(PI/3), 0.0);
x.rotateXYBy(30);

printf("x = [%f, %f, %f]/n", x.X, x.Y, x.Z);

输出:

x = [-0.000000, 2.000000, 0.000000]

就是前面通过两步得出的结果。上面irrlicht代码需要注意的是,参数是degree是表示单位是度数,其他时候都默认为弧度。

D3D中使用下列函数实现旋转,没有实现源代码,没有太多好说的。

// Build a matrix which rotates around the X axis
D3DXMATRIX* WINAPI D3DXMatrixRotationX
    ( D3DXMATRIX *pOut, FLOAT Angle );

// Build a matrix which rotates around the Y axis
D3DXMATRIX* WINAPI D3DXMatrixRotationY
    ( D3DXMATRIX *pOut, FLOAT Angle );

// Build a matrix which rotates around the Z axis
D3DXMATRIX* WINAPI D3DXMatrixRotationZ
    ( D3DXMATRIX *pOut, FLOAT Angle );

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

<script type="text/javascript">var sitebro_tracker_atc_kw = {u:'http://www.sitebot.com.cn/754892/',w:'NzU0ODky',bt:'#804000',bg:'#EEEEDD',fs:1,ca:'#770000',bh:'#f4f4c6',cp:'',l:10,s:1,lang:'zh_CN'};</script><script type="text/javascript" src="http://www.sitebot.com.cn/js/widget_track2/tracker_atc_kw.js"></script><script type="text/javascript"><!-- var sitebro_tracker_atc={u:'http://www.sitebot.com.cn/754892/',w:'NzU0ODky',bt:'#804000',bg:'#EEEEDD',cf:'#ffffff',ca:'#770000',bh:'#DDDDCC',cp:'%E6%9C%AC%E7%AB%99%E7%83%AD%E9%97%A8%E6%96%87%E7%AB%A0',l:10,s:0,lang:'zh_CN'}; // --></script><script src="http://www.sitebot.com.cn/js/widget_track2/tracker_atc.js" type="text/javascript"></script>
分享到:
评论

相关推荐

    3D数学基础:图形与游戏开发(中英文版和源码)

    《3D数学基础:图形与游戏开发》主要介绍了基本的3D数学概念,这对电脑游戏开发人员和编程人员来说尤为重要。作者详尽地讨论了数学理论,并在必要时提供几何说明,帮助读者形成直观的3D感。书中还提供了将理论应用于实践...

    [3D数学基础:图形与游戏开发].(3D.Math.Primer.for.Graphics.and.Game.Development).pdf

    《3D数学基础:图形与游戏开发》主要介绍了基本的3D数学概念,这对电脑游戏开发人员和编程人员来说尤为重要。作者详尽地讨论了数学理论,并在必要时提供几何说明,帮助读者形成直观的3D感。书中还提供了将理论应用于...

    3D数学基础 图形与游戏开发

    《3D数学基础:图形与游戏开发》主要介绍了基本的3D数学概念,这对电脑游戏开发人员和编程人员来说尤为重要。作者详尽地讨论了数学理论,并在必要时提供几何说明,帮助读者形成直观的3D感。书中还提供了将理论应用于...

    [3D数学基础:图形与游戏开发]扫描版

    《3D数学基础:图形与游戏开发》主要介绍了基本的3D数学概念,这对电脑游戏开发人员和编程人员来说尤为重要。作者详尽地讨论了数学理论,并在必要时提供几何说明,帮助读者形成直观的3D感。书中还提供了将理论应用于...

    精通DirectX.3D图形与动画程序设计.pdf

    附录d 计算机图形学数学基础 d.1 坐标参照系 d.2 点与向量  d.3 矩阵 d.4 四元数 附录e 计算机图形学基础 e.1 概述 e.1.1 计算机图形学的概念 e.1.2 计算机图形学的研究内容 e.2 图形系统与图形设备 e.2.1 图形系统...

    OpenGL图形变换时的矩阵和向量计算数学库GLM

    在使用OpenGL做图形加载后,根据实际需求往往需要进行平移、旋转、缩放等操作,在三维坐标中,通过矩阵和向量之间的各种数学运算...在用此数学库之前,需要有一定的图形变换基础知识。同时,需要具备一定的编程基础。

    DirectX9 3D游戏设计入门 英文版+中文版+源代码

    传说中的龙书是也。。。 最好最新的DirectX游戏开发入门书籍 ...Prank Luna是Hero lnteractive的程序员,从事交互式3D图形编程已有八年多。他最早接触DirectX可以追溯到DirectX5发布之时,目前居住在加州的洛杉矶市。

    OpenSceneGraph三维渲染引擎编程指南.pdf-part1

    第2章 OpenSceneGraph数学基础 2.1 坐标系统 2.2 坐标系变换 2.2.1 世界坐标系-物体坐标系变换 2.2.2 物体坐标系-世界坐标系变换 2.2.3 世界坐标系-屏幕坐标系变换 2.3 向量、矩阵及四元数 2.3.1 向量 2.3.2...

    OpenSceneGraph三维渲染引擎编程指南.pdf-part2

    第2章 OpenSceneGraph数学基础 2.1 坐标系统 2.2 坐标系变换 2.2.1 世界坐标系-物体坐标系变换 2.2.2 物体坐标系-世界坐标系变换 2.2.3 世界坐标系-屏幕坐标系变换 2.3 向量、矩阵及四元数 2.3.1 向量 2.3.2...

    Visual Basic绘图程序设计 任德记编著

    第四节 二维图形矩阵变换 一、点的变换 二、直线的变换 三、平面的变换 四、齐次坐标 五、组合变换及举例 习题 第四章 物体视图及表面展开 第一节 物体视图的变换矩阵 一、三维基本变换矩阵 二、三视图变换矩阵 第...

    OpenSceneGraph三维渲染引擎编程指南

    第2章 OpenSceneGraph数学基础 27 2.1 坐标系统 28 2.2 坐标系变换 29 2.2.1 世界坐标系-物体坐标系变换 30 2.2.2 物体坐标系-世界坐标系变换 30 2.2.3 世界坐标系-屏幕坐标系变换 32 2.3 向量、矩阵及四元数 ...

    MATLAB图像处理与界面编程宝典pdf part4

    第2部分“图像处理工具箱详解”,包括第11~第19章,详细讲解了图像处理工具的各项功能及相关函数,并对有关的图像知识(如图像变换、数学形态学、图像增强和图像复原)进行了介绍。第3部分“图像处理实务”,包括第...

    OpenSceneGraph三维渲染引擎编程指南.pdf

    第2章 OpenSceneGraph数学基础 27 2.1 坐标系统 28 2.2 坐标系变换 29 2.2.1 世界坐标系-物体坐标系变换 30 2.2.2 物体坐标系-世界坐标系变换 30 2.2.3 世界坐标系-屏幕坐标系变换 32 2.3 向量、矩阵及...

    《Visual C++数字图像处理开发入门与编程实践》源码

    2.3 MFC编程基础 38 2.3.1 MFC应用程序框架 39 2.3.2 Windows消息和事件驱动 40 2.3.3 常用消息 41 2.3.4 MFC的消息映射 42 2.4 消息与事件响应 44 2.4.1 添加类 44 2.4.2 添加类成员 45 2.4.3 添加消息响应 46 ...

    vector-display-graphics-engine:70年代80年代矢量显示游戏的图形引擎,例如Asteroids Lunar Lander。 用“ C”编程语言编写,包含数学函数(三角函数,角度转换,矩阵变换和矩阵乘法),原始图形(点,线,强度,矢量屏幕闪烁),字体和利用SDL v2的渲染引擎

    矢量显示图形引擎(vEdge) 概述 我决定使用简单直接媒体库版本2(SDL v2)编写Lunar Lander游戏。 首先,我不得不为这些类型的游戏编写一个游戏引擎,此回购诞生了。 目前,它仅支持2D矢量显示,这是我的Lunar ...

    精通matlab7.0混合编程.

    第3章 matlab混合编程简介 3.1 进行混合编程的出发点 3.2 matlab应用程序接口简介 3.3 几种常见的混合编程方法简介 3.3.1 使用matlab自带的matlab compiler 3.3.2 利用matlab引擎 3.3.3 利用activex控件 3.3.4 利用...

    MATLAB教程

    MATLAB基础知识 3 第 1 节 Matlab 基本知识 3 一、 Matlab 的主要功能 3 二、 Matlab 的界面 3 M-文件(函数文件) 3 Matlab帮助系统 4 三 、关于变量 4 第 2 节 Matlab编程 5 一、 矩阵(数组)的输入 5 二、 矩阵...

    [Flash.ActionScript.3.0动画教程

    第18章 矩阵数学 18.1 矩阵基础 18.2 矩阵运算 18.2.1 矩阵加法 18.2.2 矩阵乘法 18.3 Matrix类 18.4 小结 第19章 实用技巧汇集 19.1 布朗(随机)运动 19.2 随机分布 19.2.1 方形分布 19.2.2 圆形分布 19.2.3 偏向...

Global site tag (gtag.js) - Google Analytics