登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> clq站长各处正式文章收集勘误 >> 主题: 学前班游戏开发入门3:Unity3D中的旋转与引出的四元数知识[原百家号文章]     [回主站]     [分站链接]
学前班游戏开发入门3:Unity3D中的旋转与引出的四元数知识[原百家号文章]
浏览(295 + ) 作者: clq  发表于 2018-03-12 11:34:44   编辑 关键字:

原文地址 https://baijiahao.baidu.com/s?id=1594555750467206968
是我发表于百家号 "clq的程序员学前班" 的文章。这篇文章比较重要,百家号嘛就目前来看还是不太靠谱,所以还是自己备份一下为好。
--------------------------------------------------
学前班游戏开发入门3:Unity3D中的旋转与引出的四元数知识

clq的程序员学前班
2018-03-1022:10
我们百家号"运营"这么一段时间以来,感觉太过具体的或者说过于专业的内容不是太受欢迎。比如前面邮件收发相减的内容,那系列在 cnblogs 可是异常火爆的,而且笔者花的心思是很多的,但在百家号中的阅读量则很是惨淡 ... 我也不明白其中的原因啊,也许是百家号都是手机来的用户没有太多的时间去作达深的思考,所以经验总结类的比较受欢迎,具体技巧的则大家就没时间多看了。这系列的 Unity3D 也是这样,其实这些知识对于入门来说还是很重要的,要知道 Unity3D 的坑那是一点都不少 ... ... 不过也不要紧,大家可以先大概了解一下,以后用到时记得回来仔细看就行了。

今天要说的是 Unity3D 中的旋转,普通的旋转在 u3d 中是相当简单的,例如这样:

obj.transform.Rotate(0, 0, 90);

其中的三个参数就是三维方向上的角度度数,只要学过初中的知识这些很容易就能用起来了。但在 u3d 中有一个操作非常的常见,那就是让一个物体看向另外一个物体,比如让摄像机一直跟着主角色。这在 u3d 中也是非常的简单,例如:

obj.transform.LookAt(target);//看向某个物体

好了,当我们把这种方法应用到让一个物体跟着另外一个物体走的时候就会出现奇怪的现象:这时候很可能不是物体的正面面向了另外一个物体,而是反面或者是侧面面对的其他物体。这是为什么呢?原因是因为这个 lookat 函数默认是让物体的 z 轴对向物体,而我们要操作的这个物体很可能是从 3dmax 或者 maya 中导入的,它们的坐标轴和 u3d 的通常是不一样的,所以很多教程在文章说会特别说明在导出模型时要先设置轴的一些参数。这个办法当然不错,但有时候这个模型是别人已经导出的,通过还附有别的参数,是不能重新导出轴参数的。这时候就要先计算出旋转的参数后再绕着自身的坐标再旋转那个轴与 u3d 轴的差值。这个算法如果要用我们高中学过的三角函数来算的话相当的繁琐,在网上的解决方案五花八门,可惜都不是太正确,如果真要算的话,正确的代码如下:

//obj.transform.rotation = Quaternion.LookRotation(target.transform.position - obj.transform.position, Vector3.up); //先看向目标

//obj.transform.rotation = obj.transform.rotation * Quaternion.Euler(new Vector3(90, 0, 0)); //再调整自身的坐标

q4 = Quaternion.LookRotation(target.transform.position - obj.transform.position, Vector3.up); //先看向目标

q4 = q4 * Quaternion.Euler(new Vector3(90, 0, 0)); //再调整自身的坐标

obj.transform.rotation = q4;

代码用了两种方向,如果直接操作物体的旋转参数的话,那么会看到物体动来动去显然不行,所以要计算出两步合成的结果后再一次性赋值给旋转参数比较好。

而要把两步的结果合成成一个,用三角函数算的话大家基本上算不出来吧 ... ... 也不用自卑,数字家们也曾经头痛过很长时间,据说解决这个问题的数字家是爱尔兰的数学家Hamilton,他用到的解决方法就是我们这次要说的4元数。也不用害怕这个没见过的"4元数",它的意思其实只是说一个数据用4个数字表示,也不一定就用来表示角度,只不过在这里我们特指一个旋转的3维空间下的参数用4个浮点来表示,也就是一个角度用4个数据才能表示出来,而我们以前学的几何中则是用3个数据就表示出来了(分别指定 x,y,z 三个轴上要旋转的角度就可以了)。按一般的教程,这里要狠狠地说一个4元数的各个解释,不过我想说的是现在的软件开发,特别是游戏开发是应用科学,不应该也不用去细究那么多,我们只要理解它是一个表示旋转角度的参数就可以,然后记住操作它的那几个函数就可以了(没有几个)。具体的函数大家可以再去查资料,这其中有一个方法一定要告诉大家,在 u3d 里,两个4元数相乘就是物体先旋转到第一个角度然后再旋转到第二个角度。这种用运算符号来表示某种结果的做法在 u3d 中很普遍,我个人觉得很不好,虽然用习惯了会觉得很方便,但是假如有一个没学过的人看以上代码肯定是不明白的,所以我觉得应该封装成函数,不应该暴露那么多数字的细节。类似的两个三维空间位置相减会得到它们的向量差(例如前面的 target.transform.position - transform.position),这也是很让初学者崩溃的。另外向量这个词也很让人要回忆高中数字的,其实从应用的角度来说,可以认为是用三个方向上的数值来表示的角度 -- 所以在 u3d 有多种表示角度的方法:Quaternion(四元数)、欧拉角(其实就是三个轴上分别转动的角度)、向量(其实就是在三个方向上的长度)。这当中当然是四元数最难理解了,所以我们干脆就不要去理解好了。

当然了,以上是学院派的做法,实际上更多的做法是先建立一个空物体,然后把模型拉成空物体的子级(见下图),然后在设计期间在里面旋转调整模型的角度就可以了,而外层空物体当做正常模型来使用就可以了。让它直接 lookat 目标就行,不用两次代码进行调整:



空物体做父级可轻松解决导出模型轴问题

大家肯定松了一口气。但这还不算完,如果是操作摄像机那没什么好说的,如果是操作模型,直接转向是很生硬的,通常会加上一个渐变的过程,所以具体的代码实际上要变成正面这样:

ship1.transform.rotation = Quaternion.Slerp(

ship1.transform.rotation,

Quaternion.LookRotation(target.transform.position - ship1.transform.position), //两个位置在前后是不一样的,原物体位置在前是最好的

//还可以这样在最后的结果上再做调整,两个角度相乘就是角度叠加了

//Quaternion.LookRotation(target.transform.position - ship1.transform.position) * Quaternion.Euler(new Vector3(90, 0, 0)), //欧拉角度转 Quaternion, //两个位置在前后是不一样的,原物体位置在前是最好的

//10 * Time.deltaTime);

2.5f * Time.deltaTime);//速度



//transform.Rotate(0, 0, 90);//ok//不行,很抖动

具体的大家可以查 Quaternion.Slerp() 函数的用法,总的来说它就是在两个角度状态之间根据不同的速度计算出二者的渐进值。要特别说明的是原物体的位置最好作为第一个参数,要不可能是没有渐变平滑效果出来的。

好了,这就是我们今天要说的内容。我知道大家一定都没听懂,不过没关系,大家记得需要的时候回来这里查看就行了。


[2018-03-12 11:38:56 最后更新]

clq
2018-03-12 11:36:26 发表 编辑

[图片]

原文配图:



总数:1 页次:1/1 首页 尾页  
总数:1 页次:1/1 首页 尾页  


所在合集/目录
u3d四元数 更多



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1