Unity3D数学

一、向量的点乘和叉乘

Unity中常常需要判断一个物体相对于另外一个物体的方位,这里假设两个物体的y轴坐标都为0。抛出如下问题。

假设A是一个巡逻的怪物,B是玩家,请问如何判断B相当于A的位置?

1.点乘

向量的点乘就是将两个向量互相相乘,举个例子A(x1,y1,z1),B(x2,y2,z2),那么A和B点乘的结果是一个新的向量C(x1*x2,y1*y2,z1*z2)

Unity中提供了点乘的方法Vector3.Dot方法,通过向量点乘可以求两个向量之间的夹角,这个夹角的意思如下图

通过点乘就可以获得角度A,具体如下代码所示

result = Vector3.Dot(this.transform.forward, (target.position - this.transform.position).normalized);
print("角度:" + Mathf.Acos(result) * Mathf.Rad2Deg);

这里的this就是A物体,target就是B物体。值得注意的是,求点乘需要使用单位向量,避免结果出错,之后再利用反三角函数得出弧度后再转成角度即可。注意这里得出的角度是A物体的面朝向和向量AB之间的夹角。

这是原理,实际上Unity中提供了求两个向量之间夹角的函数即Vector3.Angle,所以上述代码可以简化成如下

 print("角度2:" + Vector3.Angle(this.transform.forward, target.position - this.transform.position));

虽然方法很简单,但是希望各位懂得原理。

这样就可以回答开始提出的问题,可以说B相对于A的正前方偏移了X度。那么向左偏移还是向右便偏移呢? 

这就需要叉乘了。

2.叉乘

同样简单叙述下向量A和向量B叉乘的结果:(y1 * z2 - y2 * z1, x1 * z2 - x2 * z1, x1 * y2 - x2 * y1),依然是一个向量,请注意以上是A×B的结果,A×B =-B×A,这点很重要。

叉乘有什么几何意义呢?首先要明白A叉乘B得到的向量是什么,它是A向量和B向量组成的平面的法线向量,就是垂直于这个平面的向量,把开始的问题放到三维空间中

紫色的向量C就是A的面朝向向量A.transform.forward和向量AB的叉乘得到的法线向量。这个法线向量的Y值是大于0的,这个时候就可以判断出B在A的右侧,如果C的Y 值小于0,那么B就在A的左侧。

同样的Unity中也有自带的求叉乘的方法Vector3.Cross。根据上述说的原理,可以这样写

         C = Vector3.Cross(A.position, B.position);
        print(D.y > 0 ? "B在A右侧" : "B在A左侧");

此API直接两个物体的位置坐标就可以了。

至此先求点乘再求叉乘,可以这么描述B相对于A的位置,B在A正前方向右偏移X度的方向上,至于距离,直接用Vector3.Distance求就可以了。

点乘和叉乘的作用还有很多,这里先留白,后面遇到了还会来补充。

二.四元数

1.为什么用四元数

Unity编辑界面物体transform的rotation几个值是物体绕几个轴的旋转的欧拉角。欧拉角是存在问题的。

首先是物体旋转的角度不是唯一的。

把一个物体的Rotation的Y设置成45和405物体呈现出来的姿态是一样的。假设要实现一个效果,物体绕Y轴旋转的角度等于45度就爆炸。条件是不可以直接写this.transform.rotation.eulerAngles.y =45。因为角度是405度也要爆炸。这只是一个简单的例子,当然可以完善,但是用四元数就真的可以写成 = 45.

其次就是万向节死锁问题。这个问题我不好描述,你可以去搜一搜这个问题所在。你可以复现这个问题。

创建一个立方体,把它的欧拉角设置为(90,0,0),然后再去拖动欧拉角的y值,你会发现此时物体并不是绕着Y轴旋转,而是绕着Z轴转。这就是万向节死锁的一个复现。具体的原理你可以去别的博客看一下。四元数就可以解决这个问题。

四元数就可以解决这两个问题。

2.四元数的表示

Unity中四元数是这样表示的,物体的任何形式的旋转都可以归纳为绕着一个轴旋转X度。假设物体绕着轴n(x,y,z)旋转β度。那么四元数可以这样表示[x*sin(β/2),y*sin(β/2),z*sin(β/2),cos(β/2)]。这其中的原理你可以找论文去看。

我们当然不可能在Unity中这样声明一个四元数,可以使用这样的方法声明一个四元数

Quaternion q = Quaternion.AngleAxis(60, Vector3.up);

AngleAxis是轴角对初始化。上面的代码的意思是这个四元数让物体绕自身的Y轴旋转60度得到的四元数。

此外还可以通过欧拉角和四元数的转换,如下面的代码

Quaternion q = Quaternion.Euler(60, 0, 0);

这句代码的意思就是把物体绕X轴旋转60度的欧拉角转换为了四元数。

3.四元数的计算

1.两个四元数相乘得到一个新的四元数,这就代表着可以通过四元数相乘的方法让物体旋转起来

this.transform.rotation *= Quaternion.AngleAxis(20, Vector3.up);

这句代码放在Update函数中物体就可以真正绕着自身的Y轴转。无论物体的初始欧拉角是什么样子,物体此时始终会绕着自己的Y轴旋转,这就解决了万向节死锁的问题。

此外,物体旋转时,观察Inspector界面transform的rotation的y值,可以看到值一直在-180到180之间变化,这就解决了物体旋转的角度不是唯一的问题。比如物体旋转角度作为45度就直接爆炸,那么可以通过四元数将物体旋转,然后判断它的欧拉角的y值,等于45度直接爆炸,是没有问题的。

2.四元数乘向量

这是一个很重要的东西。用一个四元数乘以向量返回的是一个新的向量,注意顺序,必须是四元数乘向量。

        Vector3 v = Vector3.forward;
        v = Quaternion.AngleAxis(45, Vector3.up) * v;

这两句代码意思就是把向量(0,0,1)绕着世界坐标轴y轴旋转45度,得到的向量就是(0.707,0,0.707),0.707就是二分之根号二。想一下把一个向量旋转有什么作用

这就很牛逼了。比如我要发射一枚rpg,我希望发射的角度是斜上方,那么这个时候就可以用rpg的面朝向乘以一个偏移的四元数,那么就可以得到一个斜向的发射方向。还不牛逼吗。

暂时就说到这里,当然还有很多数学,后面遇到再来补充。

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值