[unity3D基础篇02]必备的3D数学基础1

来源:互联网 发布:订货软件 编辑:程序博客网 时间:2024/06/16 04:13

今天东京在下雨不想出门,趁此时间来整理一点unity学习中的数学问题。昨天上完了VR课程的第二堂课,感觉有50%没有听懂...尴尬 

制作一个VR应用很简单,但是真正要深入去理解的话比较困难。比如在佩戴VR设备的时候大多会有头晕的体验,一方面原因是硬件设备问题(分辨率,帧率等),还有个重要的原因就是应用的设计,对资源(模型渲染材质)的利用等存在问题,一般帧率在达到90fps的时候可以减少头晕,也就是11ms/帧来播放(研究报道人眼对画面刷新的分辨率约是0.01s)。当然还有很多其他因素,比如视野角,一般约是110度。

扯的有些远了。。回到这次的主题,在学习3D引擎比较难也是很重要很基础的东西-3D空间中的数学。下面开始整理下学到的一点点东西。之后慢慢补充。

1. 最基础的基础向量

真是大学学的东西基本已经还给老师了。。

概念:向量是一条有大小和方向的线段。区别于点(无方向)。向量中的数表达了向量在每个维度上的有向位移。


1.1 向量的加减法

比如:我们如果用点A减去点B,则可以得到一个向量,该向量的方向为点B指向点A的方向,而大小为两点的距离。

在U3D中,统一用Vector3对象来表达向量和点,何时代表向量对菜鸟的我来说比较难把握。

比如在游行中计算两个点之间距离时,用到向量。在API中有两种方法:

Vector3 v1,v2

float disv1= Vector3.Distance(v1, v2);  该函数中v1,v2是点

floatdisv2 = (v1 – v2).magnitude;   该函数中v1,v2是向量


比如:自动寻路中,当前对象要实时转向目标对象,然后向目标靠近。

这里要用到 Quaternion.LookRotation 注视旋转 函数。来看下文档中对它的描述:Creates a rotation with the specified forward and upwards directions。它返回一个四元数。四元数是什么我也不知道。。它应该可以表示空间中的旋转。既然又提到了选择,那不得不稍微深入学习下了。。

旋转大概是3D空间中相对位移,缩放的最复杂的一种了(对我来说= =0)  

旋转的表示方法四元数。 旋转矩阵。 欧拉角

a) 首先来看欧拉角(Euler angles)说实话查了一些资料我也没看懂太多。。总之如何在游戏中使用是需要知道的。

欧拉旋转,我们最常用的旋转方法应该是使用yaw, roll和pitch。


               

Unity中的旋转是通过欧拉角进行调整。来看下Transform组件中的eulerAngles属性。类型:Vector3。

如使物体每秒沿着y轴旋转10度:

   transform.eulerAngles += new Vector3(0, 5f, 0)或 transform.Rotate(0,5f,0); transform.Rotate(Vector3.up);

当然这个轴是自身坐标还是世界坐标系里面的轴是不同的。如:

  transform.Rotate(new Vector3(0,5f,0), Space.Self);//绕自身坐标系的y轴每秒五度的旋转

此处引出静态欧拉角和动态欧拉角。使用Space.World旋转,以及 Editor 中的旋转,是静态欧拉角;使用Space.self,是动态欧拉角。

知识点1:unity的本地坐标系和世界坐标系都是左手坐标系,使用左手法则。

知识点2: 旋转的顺序。可以参考这个链接的文章:http://www.itnose.net/detail/6629269.html

旋转顺序的不同最后达到的效果也是不同的。如同坐标系中的变换矩阵。矩阵的乘法是不可逆的过程。即不满足交换律。

知识点3: 由于万向节锁的存在,欧拉旋转无法实现球面平滑插值。线性插值的问题下一篇再详细查一下再记录下吧。

对于Unity,从文档中可以看到,使用的是Z-X-Y顺规,这是一种常用的顺规,可以一定程度上避免万向节锁。万向节锁(Gimbal Lock)简单理解下就是指在旋转过程中出现多个坐标轴的重合。)

   动态欧拉角除了上面说到的顺规问题,还有一个额外的疑问:比如一个物体,初始状态记为A,以zxy顺规旋转(90,90,0),由于没有z轴旋转,第一步当然是绕着当前的x轴旋转90度,此时状态记为B,那么第二步要绕着y轴旋转90的时候,是绕着初始状态A时的y轴旋转,还是绕着此时的B状态下的y轴旋转呢?

 如在unity中运行下面代码(原物体0,0,0点无旋转) 出现效果如下图:

transform.Rotate(new Vector3(90, 90, 0), Space.Self);

如果把上面这行代码分开来执行:

transform.Rotate(new Vector3(90, 0, 0), Space.Self);transform.Rotate(new Vector3(0, 90, 0), Space.Self);



可以看出,虽然都是x轴旋转90度,y轴旋转90度,就是因为先后执行和一起执行的不同导致的旋转效果大不相同。

最终结论是:每次使用Space.self进行rotate时,都是绕着调用时刻的坐标轴进行旋转的。

现在应该和我一样有疑问了吧。文档中不是明明说了旋转顺序是Z、X、Y吗?怎么现在完全反过来了呢?

原因就是我们之前说的两种坐标系的选择。在一次调用transform.Rotate的过程中,坐标轴是不随每次单个坐标轴的旋转而旋转的。而在调用transform.Rotate后,这个旋转坐标系才会变化。

知识点n:在Space.World中以Z-X-Y 归顺旋转角度(a1、a2、a3),等价于在Space.Self中分别顺次旋转(0,a2,0)、(a1,0,0)、(0,0,a3)

总结:欧拉角eulerAngles在Unity3D是一个Vector3类的变量,官方约定俗成的层级关系是ZXY,即最里层是Z轴先旋转,中间层是X轴,最外层是Y轴。

        unity中的欧拉角有两种方式可以解释:
        1,当认为顺序是yxz时(其实就是heading - pitch - bank),是传统的欧拉角变换,也就是以物体自己的坐标系为轴的。
        2,当认为顺序是zxy时(roll - pitch - yaw),也是官方文档的顺序时,是以惯性坐标系为轴的。后者比较直观一些,但其实两者的实际效果是一样的,只是理解不一样。
无论以何种方式旋转三个轴,都会有出现万向锁的情况,万向锁主要在动画里面旋转时出现我们不希望见到的旋转路径,所以官方以ZXY顺序来旋转的时候可以最大程度上避免普通情况下会出现的万向锁。

有关欧拉角的知识点太多了,这次就先暂时总结上面这些。还有很多看了一下午也没能理解。。。好吧,下面是四元数。

b)四元数: Quaternion = (xi + yj + zk + w ) = (x,y,z,w)

四元数也是个比较抽象的概念。我们可以使用一个四元数q=((x,y,z)sinθ2cosθ2) 来执行一个旋转.具体来说,如果我们想要把空间的一个点P绕着单位向量轴u = (x, y, z)表示的旋转轴旋转θ角度.

先看下unity的api中的四元数类:Quaternion

常用函数:

  1)Euler :回一个旋转角度,绕z轴旋转z度,绕x轴旋转x度,绕y轴旋转y度(像这样的顺序)。

比如实现上面的绕y轴旋转:

transform.rotation = Quaternion.Euler(new Vector3(0,ySpeed,0));

 2)AngleAxis角轴。绕axis轴旋转angle,创建一个旋转。参数是旋转的角速度和轴方向(向量)。

同样实现上面的效果:transform.rotation = Quaternion.AngleAxis(ySpeed,Vector3.up);

3)LookRotation: Creates a rotation with the specified forward and upwards directions.

该函数经常用于敌人寻找玩家。如:

Quaternion enemy_q = Quaternion.LookRotation(enemy.position - target.position);

enemy.rotation = enemy_q;

enemy.transform.Translate (Vector3.forward * enemy_speed);

4) Slerp 产生一个匀速的旋转。如果想用它产生匀速转动

Quaternion.Slerp(transform.rotation, TargetRotation, speed);


比较

  • 变换矩阵

可以做各种复杂的变换,但是学**曲线比较大,使用的内存也比较多,因为存储的数据量比较大。

  • 欧拉角

简单理解,尤其是对美术和策划的同事。运算速度和消耗内存比较少。可能存在万向锁的问题(两个轴的旋转重合)

  • 四元数

避免了万向锁的问题。理解起来不是那么直接。

这次先记录这么多吧,下次再更新。可怜





0 0
原创粉丝点击