【转载】Unity中矩阵的平移、旋转、缩放
年代久远,图片链接失效了,这里重新放一个腾讯学院的版本,里面有图片
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中矩阵的平移、旋转、缩放的更多相关文章
- osg中使用MatrixTransform来实现模型的平移/旋转/缩放
osg中使用MatrixTransform来实现模型的平移/旋转/缩放 转自:http://www.cnblogs.com/kekec/archive/2011/08/15/2139893.html# ...
- osg矩阵变换节点-----平移旋转缩放
osg矩阵变换节点-----平移旋转缩放 转自:http://www.cnblogs.com/ylwn817/articles/1973396.html 平移旋转缩放这个三个是osg矩阵操作中,最常见 ...
- 【Unity编程】Unity中的欧拉旋转
欧拉角的定义 在写这篇博客之前,我搜索了网上很多关于欧拉角的定义,发现大部分引用自维基百科的定义,我这里也引述一下: 维基百科定义 莱昂哈德·欧拉用欧拉角来描述刚体在三维欧几里得空间的取向.对于任何参 ...
- 【Qt官方例程学习笔记】Analog Clock Window Example (画笔的平移/旋转/缩放应用)
这个例子演示了如何使用QPainter的转换和缩放特性来简化绘图. 值得学习的: 定时器事件ID检查: 在定时器事件中检查定时器id是比较好的实践. QPainter抗锯齿: We call QPai ...
- webgl学习笔记三-平移旋转缩放
写在前面 建议先阅读下前面我的两篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 平移 1.关键点说明 顶点着色器需要加上 uniform vec4 u_Translation ...
- unity中全屏背景图缩放
using UnityEngine; using System.Collections; public class BgPicScript : MonoBehaviour { // Use this ...
- 【安卓】自己定义基于onDraw的随意动画(不不过平移/旋转/缩放/alpha)、!
思路: 1.基于时间的显示映射.如:给定度数,显示圆弧,加上时序,就可以有圆弧动画的效果 2.给定时序. 用于驱动动画的一帧帧绘制 方案一.基于ObjectAnimator.动画运作时会调用degre ...
- 【Qt官方例程学习笔记】Raster Window Example(画笔的平移/旋转/缩放应用)
这个例子显示了如何使用QPainter渲染一个简单的QWindow. 值得学习的内容 <QtGui>头文件 #include <QtGui>就可以使用Qt GUI模块中的所有类 ...
- Unity 中的坐标系
说明: 注意几点: 0 行向量右乘矩阵与列向量左乘矩阵,两个矩阵互为逆矩阵 1 法线转换与mul,mul函数左乘矩阵当列矩阵计算,右乘当行矩阵计算 2 叉乘与左右手系,左手系用左手,右手系用右手,ax ...
随机推荐
- 使用parted给大于2T的磁盘分区
1.使用命令parted /dev/sdb [root@server ~]# parted /dev/sdb GNU Parted 2.1 使用 /dev/sdb Welcome to GNU Par ...
- php将对象数组转成普通数组
不知道为什么,把数组序列化为json,然后存到redis(string类型).然后再取出来反序列化为数组,就变成对象数组了 thinkPHP普通数组取值$arr['key'] 对象数组取值$arr-& ...
- OpenStack Mitaka 版本中的 domain 和 admin
OpenStack 的 Keystone V3 中引入了 Domain 的概念.引入这个概念后,关于 admin 这个role 的定义就变得复杂了起来. 本文测试环境是社区 Mitaka 版本. 1. ...
- 程序设计模式浅析(plain framework商业版设计模式)
程序设计其实对程序开发者来说十分重要,但是在工作中往往我们却忽略了这一块,因为我们所用的都是现有的模式.一个设计模式的好坏,往往能够体现出程序的专业性,还有整个项目的可持续性.这就是为什么有些公司,在 ...
- Spring 设值注入 构造注入 p命名空间注入
注入Bean属性---构造注入配置方案 在Spring配置文件中通过<constructor-arg>元素为构造方法传参 注意: 1.一个<constructor-arg>元素 ...
- AC日记——地鼠游戏 codevs 1052
1052 地鼠游戏 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 王钢是一名学习成绩优异的学生,在平 ...
- python中的迭代器
1.可以直接作用于for循环的数据类型 第一类:集合数据类型,如list.tuple.dict.set.str等: 第二类:generator,包括集合定义generator和带yield的gener ...
- sql语句返回值的问题
由于执行sql语句的时候执行成功或者失败会返回执行的影响函数,用list是因为查询的结果可能为null也可能set后放到集合里去: 所以返回值类型用int
- CSS中一些常见的兼容性问题
CSS中一些兼容性问题就是浏览器兼容,而这些浏览器兼容问题主要是Ie和FF之间的争斗. CSS hack中的一些事: 我们为了让页面形成统一的效果,要针对不同的浏览器或不同版本写出对应可解析的CSS样 ...
- Media Queries
@media screen and (max-device-width: 1920px) and (min-device-width: 1920px) 指定1920分辨率的样式,使用device-wi ...