年代久远,图片链接失效了,这里重新放一个腾讯学院的版本,里面有图片

http://gad.qq.com/article/detail/33543

By:克森

简介

在这篇文章中,我们将会学到几个概念:平移矩阵、旋转矩阵、缩放矩阵。在学这几个基本概念的同时,我们会用到 Mesh(网格)、数学运算、4x4矩阵的一些简单的操作。但由于克森也是新手,文章的严谨性可能不是很高,还请大神们多多指教。

创建项目

首先创建一个Unity工程,克森把他命名为“Matrix of China”(中国的矩阵),基本配置如下图所示:

为了便于查找,让我们在 Assets 目录下新建三个文件夹,分别命名为“Scripts”、“Shader”、“Materials”,这个不用解释,大伙们都看得懂吧。如下图所示:

接下来再 Scripts 文件夹里创建一个 C# 脚本,命名为“Triangle”,该脚本用于创建一个简单的三角形。然后在 Hierarchy 面板下创建一个空物体,命名为“Triangle”。然后为该物体添加之前创建的“Triangle”脚本,且为该物体添加 Mesh 相关的两个组件,如下图所示:

好,接下来让我们开始码了个码。

Triangle.cs

首先让我们看一看完整的代码,然后再一步一步的分析:

代码解析

相信这段代码对于大伙来说都不是很难吧。创建一个网格的步骤一般都是按这个顺便来创建的:

1.为顶点数组赋值

2.为三角形数组赋值

在代码中的“vertices”就是所谓的顶点数组、”triangles“就是所谓的三角形数组,它的作用其实就是对应顶点的索引。一般一个三角形是由三个顶点组成的。

好,让我们回到 Inspector 面板修改一下“Triangle”脚本的属性,如下图所示:

PS:三角形数组索引必须从0开始,按顺序然后自增 1。且再次强调,三个顶点才能构成一个三角形。

好,现在让我们点击 Play 进行测试一下:

Okey,现在我们的三角形算是完成了,接下来开始玩弄它了。

脚本中的变换

首先创建一个 C# 脚本,命名为“MyTransform”,并为我们的“Triangle”物体添加此脚本。代码如下:

代码解析

这段代码很简单,就是声明一个 4x4 的矩阵,然后调用该 4x4 矩阵的 SetTRS 函数(T 代表 Translate(平移)、R 代表 Rotation(旋转)、S 代表 Scale(缩放))。该函数用来设置一个平移、旋转、缩放矩阵。在代码中,我们传入的是该物体的 position、rotation、localScale,这样做是为了便于观察相应的变换矩阵。

1平移矩阵

这个就是平移矩阵,其中 (Tx,Ty,Tz) 为平移的方向向量,有些书上是把 Tx、Ty、Tz 放在第四行,当经过克森的测试,Unity的平移矩阵式这样子的。下面我们就做一个简单的测试:

1.修改“Triangle”的 Position 为(1,2,3)

2.点击 Play 按钮,观察一下 matrix 属性的变化:

图中画红线的“E03”、“E13”、“E23”正好就是对应上面平移矩阵图中的“Tx”、“Ty”、“Tz”,这说明Unity使用的正是这种方式的平移矩阵。

接下来,我们利用平移矩阵做个简单的平移,让我们回到“MyTransform”脚本中添加一些代码:

代码解析

之前在 Start 函数里的代码注释掉,因为文章的后面还要用到。在代码中,新添加了一个 Vector4 类型的变量,这是因为 4x4 的矩阵不能与三维向量相乘。

之后再 Start 函数中初始化了向量和矩阵,变量“v”存放的是当前物体的位置,而当前的矩阵为单位矩阵(对于矩阵的乘法和单位矩阵我就不想讲了,请大伙自行百度学习)。

然后找到矩阵中对应的平移的方向“Tx”、“Ty”、“Tz”,在代码中,我让物体向 X 轴方向平移3个单位、Y 轴方向平移4个单位、Z 轴方向平移5个单位。

之后执行矩阵变换的操作,矩阵的操作如下图所示:

最后将计算的结果传给物体的 Position。然后在 Start 函数里调用一下该函数:

PS:记得将“Triangle”物体的 Position 设置为 (0,0,0)。现在让我们点击 Play 查看一下结果对不对:

好了,值是正确的。大家也可以修改一下参数玩玩。至此,平移矩阵大体讲完了,还是有点懵的伙计可以给克森说说。

缩放矩阵

这个就是缩放矩阵,其中“Sx”、“Sy”、“Sz”就是各个轴上的缩放因子。缩放矩阵是矩阵表现物体大小变换的矩阵。如果缩放因子小于1,表现为物体缩小;如果大于1,则表现为物体扩大,如果等于1则不发生变化。

接下来我们做个简单的测试,把取消之前 Start 函数里的代码,然后修改“Triangle”物体的 Scale 属性为(1,2,3),点击 Play 查看一下结果:

找到对应的各个轴的缩放因子,目前来说结果是正确的了。

接下来,我们利用缩放矩阵做个简单的操作,让我们回到“MyTransform”脚本中添加一些代码:

代码解析

这段代码和之前平移的代码差不到哪里去。代码里也给了注释。主要就是矩阵的缩放操作不一样,下面弄张图就搞定了,缩放操作相对来说还是蛮简单的。

因此就有:

最后修改一下 Start 函数的代码即可:

现在点击 Play 按钮查看一下结果是否正确:

Okey,看来结果是正确的。

PS:当各个轴上的缩放因子相等时,即:Sx=Sy=Sz 时,则为均匀缩放。

旋转矩阵

上图就是所谓的旋转矩阵。在我们的实践中,我就使用沿 x- 轴进行旋转做实践即可。

首先还是做个简单的测试,让我们修改一下脚本,然后将物体的 Rotation参数设置为 (45,0,0),最后点击 Play 按钮查看结果,如下图所示:

在这里我选择了45°角,因为 sin45°和cos45° 的值是相等的(虽然在上图中他们的值不相等,但实际上是相等的,大伙们可以用个 if 语句判断一下),让我们看看结果对不对:

Okey,看来是正确的。

接下来,我们利用旋转矩阵做个简单的操作,让我们回到“MyTransform”脚本中添加一些代码:

由于图片是拼接的,所有有点别扭

代码解析

首先声明了一个 float 类型的变量“angle”用于输入需要旋转的角度,之后又声明了一个 emun(枚举) 类型的变量“Axle”,用于选择旋转的方式。

接下在“MyRotation”函数中初始化了矩阵。接下来的判断语句就是对应各个轴上的旋转(可以与上面那张旋转矩阵进行对比,相信大家都能懂吧),在判断语句中主要用到了三个函数:Mathf.Sin()、Mathf.Cos()、Mathf.Deg2Rad()。前面两个函数大家都知道是什么了吧,后面那个函数用于弧度转角度,因为前面两个函数接受的是一个弧度制的值。

接下来的代码就是做矩阵转为四元数的操作,具体请看下图中的公式:

最后将计算好的值传给物体的 Rotation 即可

All right. 现在让我们回到物体的 Inspector 面板中修改“Angle”参数 和 Axle 选项,然后点击 Play 按钮进行测试即可(在这里克森选择的是,绕 X 轴旋转45°):

Perfect. 和我们预期的效果一样,大伙们可以自行修改参数进行测试一番。

最后给大家送上一个小工具,只需传入一个变换矩阵即可帮你完成平移、旋转、缩放的工作,然后把值传给物体的 Position、Rotation、Scale:

接下来用一个例子来演示这个小工具怎么使用。

回到我们的场景中,找到“Triangle”物体,在 Inspector 面板中修改“MyTransform”脚本的“Matrix”属性,如下图所示:

红色箭头代表平移、绿色箭头代表缩放、黄色箭头代表旋转,这个变换矩阵表示的是:物体在X轴上平移3个单位、Y轴上平移4个单位、Z轴上平移5个单位(position (3,4,5));物体绕着X轴旋转90° (Rotation(90,0,0));物体没有缩放 (1,1,1) 。

然后回到“MyTransform”脚本的Start函数中调用工具类里的方法完成变换矩阵的各项操作:

最后点击 Play 按钮查看结果:

Perfect. 看来和我们预期的效果一模一样,大伙们可以自行修改参数进行测试。

好了,这篇文章就到这里了。这部分内容也是克森最近刚刚学的,也算是学习笔记吧,如果有什么错误的地方还请大神们指教指教。

附上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Tringle : MonoBehaviour { private Mesh mesh;
public Vector3[] vertices;
public int[] triangle; // Use this for initialization
void Start () {
mesh = new Mesh ();
mesh.vertices = vertices;
mesh.triangles = triangle; var meshRender = GetComponent<MeshRenderer> ();
if (meshRender == null)
meshRender = this.gameObject.AddComponent<MeshRenderer> (); var meshFilter = GetComponent<MeshFilter> ();
if (meshFilter == null)
meshFilter = this.gameObject.AddComponent<MeshFilter> (); meshFilter.mesh = mesh;
} // Update is called once per frame
void Update () { }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public enum Axle
{
X,
Y,
Z,
} public class MyTransform : MonoBehaviour { public Axle axle; public Vector4 v4; public Matrix4x4 matrix; // Use this for initialization
void Start () {
//matrix.SetTRS (
// transform.position,
// transform.rotation,
// transform.localScale
//); } void MyTranslate (float x, float y, float z) {
v4 = new Vector4 (
transform.position.x,
transform.position.y,
transform.position.z, ); /* identity
* 1 0 0 0
* 0 1 0 0
* 0 0 1 0
* 0 0 0 1
*/
matrix = Matrix4x4.identity; // pos
matrix.m03 = x;
matrix.m13 = y;
matrix.m23 = z; /* pos transform
* 1 0 0 x * pos.x 1 * pos.x + 0 * pos.x + 0 * pos.x + x * pos.x x * pos.x
* 0 1 0 y * pos.y == ... == y * pos.y
* 0 0 1 z * pos.z ... z * pos.z
* 0 0 0 1 * 1 ... 1
*/
v4 = matrix * v4; transform.position = new Vector3 (v4.x, v4.y, v4.z);
} void MyScale(float x, float y, float z)
{
v4 = new Vector4 (
transform.localScale.x,
transform.localScale.y,
transform.localScale.z, ); /* identity
* 1 0 0 0
* 0 1 0 0
* 0 0 1 0
* 0 0 0 1
*/
matrix = Matrix4x4.identity; matrix.m00 = x;
matrix.m11 = y;
matrix.m22 = z; v4 = matrix * v4; transform.localScale = new Vector3 (v4.x, v4.y, v4.z);
} void MyRotation(Axle axle, float angle)
{
matrix = Matrix4x4.identity; // set matrix
if (axle == Axle.X) {
matrix.m11 = Mathf.Cos (angle * Mathf.Deg2Rad);
matrix.m22 = -Mathf.Sin (angle * Mathf.Deg2Rad);
matrix.m21 = Mathf.Sin (angle * Mathf.Deg2Rad);
matrix.m22 = Mathf.Cos (angle * Mathf.Deg2Rad);
} else if (axle == Axle.Y) {
matrix.m00 = Mathf.Cos (angle * Mathf.Deg2Rad);
matrix.m02 = Mathf.Sin (angle * Mathf.Deg2Rad);
matrix.m20 = -Mathf.Sin (angle * Mathf.Deg2Rad);
matrix.m22 = Mathf.Cos (angle * Mathf.Deg2Rad);
} else if (axle == Axle.Z) {
matrix.m00 = Mathf.Cos (angle * Mathf.Deg2Rad);
matrix.m01 = -Mathf.Sin (angle * Mathf.Deg2Rad);
matrix.m10 = Mathf.Sin (angle * Mathf.Deg2Rad);
matrix.m11 = Mathf.Cos (angle * Mathf.Deg2Rad);
} // to quaternion
float qw = Mathf.Sqrt(1f + matrix.m00 + matrix.m11, matrix.m22) / ;
float w = * qw;
float qx = (matrix.m21 - matrix.m12) / w;
float qy = (matrix.m02 - matrix.m20) / w;
float qz = (matrix.m10 - matrix.m101) / w; transform.rotation = new Quaternion (qx, qy, qz, qw);
}
}

【转载】Unity中矩阵的平移、旋转、缩放的更多相关文章

  1. osg中使用MatrixTransform来实现模型的平移/旋转/缩放

    osg中使用MatrixTransform来实现模型的平移/旋转/缩放 转自:http://www.cnblogs.com/kekec/archive/2011/08/15/2139893.html# ...

  2. osg矩阵变换节点-----平移旋转缩放

    osg矩阵变换节点-----平移旋转缩放 转自:http://www.cnblogs.com/ylwn817/articles/1973396.html 平移旋转缩放这个三个是osg矩阵操作中,最常见 ...

  3. 【Unity编程】Unity中的欧拉旋转

    欧拉角的定义 在写这篇博客之前,我搜索了网上很多关于欧拉角的定义,发现大部分引用自维基百科的定义,我这里也引述一下: 维基百科定义 莱昂哈德·欧拉用欧拉角来描述刚体在三维欧几里得空间的取向.对于任何参 ...

  4. 【Qt官方例程学习笔记】Analog Clock Window Example (画笔的平移/旋转/缩放应用)

    这个例子演示了如何使用QPainter的转换和缩放特性来简化绘图. 值得学习的: 定时器事件ID检查: 在定时器事件中检查定时器id是比较好的实践. QPainter抗锯齿: We call QPai ...

  5. webgl学习笔记三-平移旋转缩放

    写在前面 建议先阅读下前面我的两篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 平移 1.关键点说明 顶点着色器需要加上 uniform vec4 u_Translation ...

  6. unity中全屏背景图缩放

    using UnityEngine; using System.Collections; public class BgPicScript : MonoBehaviour { // Use this ...

  7. 【安卓】自己定义基于onDraw的随意动画(不不过平移/旋转/缩放/alpha)、!

    思路: 1.基于时间的显示映射.如:给定度数,显示圆弧,加上时序,就可以有圆弧动画的效果 2.给定时序. 用于驱动动画的一帧帧绘制 方案一.基于ObjectAnimator.动画运作时会调用degre ...

  8. 【Qt官方例程学习笔记】Raster Window Example(画笔的平移/旋转/缩放应用)

    这个例子显示了如何使用QPainter渲染一个简单的QWindow. 值得学习的内容 <QtGui>头文件 #include <QtGui>就可以使用Qt GUI模块中的所有类 ...

  9. Unity 中的坐标系

    说明: 注意几点: 0 行向量右乘矩阵与列向量左乘矩阵,两个矩阵互为逆矩阵 1 法线转换与mul,mul函数左乘矩阵当列矩阵计算,右乘当行矩阵计算 2 叉乘与左右手系,左手系用左手,右手系用右手,ax ...

随机推荐

  1. 1-web应用之LAMP源码环境搭建

    目录 一.LAMP环境的介绍     1.LAMP环境的重要性     2.LAMP组件介绍 二.Apache源码安装     1.下载Apache以及相关依赖包     2.安装Apache以及相关 ...

  2. Java基础知识笔记(八:集合类)

    目录 1  集合类简介  2  List介绍及简单使用 2.1  LinkedList介绍及简单使用 2.2  ArrayList介绍及简单使用 2.3  Vector介绍及简单使用 2.3.1  S ...

  3. Unity中使用Attribute

    Attribute是c#的语言特性 msdn说明如下: The Attribute class associates predefined system information or user-def ...

  4. curl -w,–write-out参数详解

    顾名思义,write-out的作用就是输出点什么.curl的-w参数用于在一次完整且成功的操作后输出指定格式的内容到标准输出. 输出格式由普通字符串和任意数量的变量组成,输出变量需要按照%{varia ...

  5. PAT 1049. 数列的片段和(20)

    给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段.例如,给定数列{0.1, 0.2, 0.3, 0.4},我们有(0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1 ...

  6. pcl曲面重建模块-poisson重建算法示例

    poisson曲面重建算法 pcl-1.8测试通过 #include <iostream> #include <pcl/common/common.h> #include &l ...

  7. 唯物 VS 唯心

    对于唯物和唯心,我了解的并不多.我所知道的那点皮毛,也只是源于教课书.只是近来恋上了阳明大哥,而在某年的高考模拟题中,阳明竟被作为唯心主义的代表,供考生们批判.这一批搞得我着实不爽,决定要为他平反   ...

  8. [LeetCode] Best Time to Buy and Sell Stock IV 买卖股票的最佳时间之四

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  9. AAU

    AAU (Active Antenna Unit) In the MBB (Mobile Broadband) era, the astonishing growth in data traffic ...

  10. web前端开发中常用的尺寸和位置

    我们在日常web前端开发过程中,会经常用到各种尺寸和位置.通常是js做动画的时候.轮播图,滚屏动画,粒子,碰撞检测,拖拽,滚动加载等等.这里我将常用的尺寸和位置的获取进行总结,不包括canvas,SV ...