前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity 以一定角速度转向动态目标的旋转方式对比

Unity 以一定角速度转向动态目标的旋转方式对比

作者头像
汐夜koshio
发布2020-07-15 19:51:07
2.3K0
发布2020-07-15 19:51:07
举报
文章被收录于专栏:U3D

1.欧拉角旋转

代码语言:javascript
复制
public void Rotate(Vector3 eulers, [DefaultValue("Space.Self")] Space relativeTo);

就容易想到的就是transform.Rotate方法:

代码语言:javascript
复制
 RotationObj.transform.Rotate(Vector3.up * Palstance * Time.deltaTime); 

其中Palstance代表角速度。

但很快就会发现这个方法有2个很大的缺陷:

①需要利用cross值(叉积)来手动判断是绕旋转轴逆时针还是顺时针旋转

如果叉积为正,说明目标体在旋转体右侧,需顺时针旋转;

如果叉积为负,说明目标体在旋转体左侧,需逆时针旋转

具体判断如下:

代码语言:javascript
复制
 1         var cross = Vector3.Cross(RotationObj.transform.forward, offset).y;
 2         if (cross > 0)
 3         {
 4             //右
 5             if (Palstance < 0)
 6             {
 7                 Palstance = -Palstance;
 8             }
 9         }
10         else if (cross < 0)
11         {
12             //左
13             if (Palstance > 0)
14             {
15                 Palstance = -Palstance;
16             }
17         }

其中offset代表目标体与旋转体坐标间的向量。

②难以判断何时应该停止旋转,且角速度过大时很容易造成在到达目标向量附近来回鬼畜旋转

一般的考虑是,当旋转体的前方向向量transform.forward与offset小于一定阈值时停止旋转,例如:

代码语言:javascript
复制
1         var angle = Vector3.Angle(RotationObj.transform.forward, offset);
2         if (angle < .1f) 
3             return ;

但当角速度过快时,很容易错过[0,0.1]这一角度范围,但如果把范围设置过大,有没办法精准对齐,于是就造成了在目标向量附近来回鬼畜旋转的状况;

当然了,也可以用一种非常生硬的方式来解决:

代码语言:javascript
复制
1         //基于当前角速度一帧内最大的旋转角度
2         if (angle < Palstance * Time.deltaTime)
3         {
4             RotationObj.transform.forward = offset;
5         }

即设置另一个阈值范围(并且这个阈值范围最好和当前角速度正相关,可以计算出基于当前角速度一帧内最大的旋转角度进行设置),当小于该阈值范围时直接瞬切,因为本来就是在一帧内的角度运动,所以不会有任何违和感。

也可以考虑将判定范围与该旋转阈值设置为同一个。完整旋转方式如下:

代码语言:javascript
复制
 1         //基于当前角速度一帧内最大的旋转角度
 2         if (angle < Palstance * Time.deltaTime)
 3         {
 4             RotationObj.transform.forward = offset;
 5             return;
 6         }
 7 
 8         var cross = Vector3.Cross(RotationObj.transform.forward, offset).y;
 9         if (cross > 0)
10         {
11             //右
12             if (Palstance < 0)
13             {
14                 Palstance = -Palstance;
15             }
16         }
17         else if (cross < 0)
18         {
19             //左
20             if (Palstance > 0)
21             {
22                 Palstance = -Palstance;
23             }
24         }
25         RotationObj.transform.Rotate(Vector3.up * Palstance * Time.deltaTime);

上面的方式经过调整后虽然能够实现准确转向,但看上去并不简单直接,那有没有更简洁快速的旋转方式呢。

2.插值旋转

代码语言:javascript
复制
Lerp(a,b,t);

旋转朝向实际上可以认为是对transform.forward进行关于角速度的插值变化:

代码语言:javascript
复制
RotationObj.transform.forward = Vector3.Lerp(RotationObj.transform.forward, offset, Time.deltaTime * Palstance / angle).normalized; 
Time.deltaTime/(angel/Palstance)=Time.deltaTime * Palstance / angle;

利用当前角度与角速度相除计算出当前帧率下的预计旋转时间,随后用当前帧率与预计旋转时间的比值来对两个向量进行插值。

这种方法非常简单,但也有一个问题是没办法做到匀速旋转,角色的朝向,当前帧速率和角度可能会随时发生变化。

3.四元数旋转

代码语言:javascript
复制
1         Quaternion q = Quaternion.LookRotation(offset);
2         RotationObj.transform.rotation = Quaternion.RotateTowards(RotationObj.transform.rotation, q, Palstance * Time.deltaTime);

四元数类中自带朝向旋转的方法,但需要先转换出目标向量对应的四元数。该方式可以实现匀速率旋转。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-07-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档