[转]游戏动画中欧拉角与万向锁的理解

2023-11-30 20:08

本文主要是介绍[转]游戏动画中欧拉角与万向锁的理解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       我在2009年5月份左右拜读了《3D数学基础:图形与游戏开发》,当时对欧拉角中万向锁的概念一直是百思不得其解,也从未遇到过这种情况。书上有这样一句话:“如果您从来没有遇到过万向锁情况,你可能会对此感到困惑,而且不幸的是,很难在本书中讲清楚这个问题,你需要亲身经历才能明白。”今天我用3个多小时的时间再次回想了一下这个问题,总算想明白了,现在把思考的结果分享给大家.

 

    下面我想说明四个问题:

1,什么是欧拉角?

2,万向锁是一种什么现象?

3,游戏动画中遇到万向锁时会发生什么?

4,怎样解决万向锁这个问题?

 

一,什么是欧拉角?

    用一句话说,欧拉角就是物体绕坐标系三个坐标轴(x,y,z轴)的旋转角度。

在这里,坐标系可以是世界坐标系,也可以是物体坐标系,旋转顺序也是任意的,可以是xyz,xzy,yxz,zxy,yzx,zyx中的任何一种,甚至可以是xyx,xyy,xzz,zxz等等等等。。。。。。所以说欧拉角多种多样。欧拉角可分为两种情况:

   1,静态:即绕世界坐标系三个轴的旋转,由于物体旋转过程中坐标轴保持静止,所以称为静态。

   2,动态:即绕物体坐标系三个轴的旋转,由于物体旋转过程中坐标轴随着物体做相同的转动,所以称为动态。

对于分别绕三个坐标轴旋转的情况,下述定理成立:

物体的任何一种旋转都可分解为分别绕三个轴的旋转,但分解方式不唯一。如:

假设绕y轴旋转为heading,绕x轴旋转为pitch,绕z轴旋转为bank,则先heading45°再pitch90°等价于先pitch90°再bank45°。

 

二,万向锁是一种什么现象?

    对于动态欧拉角,即绕物体坐标系旋转。(静态不存在万向锁的问题)无论heading和bank为多少度,只要pitch为±90°(即绕第二个轴的旋转),就会出现万向锁现象。

    为了对这一现象有一个感性的认识,请拿起自己的手机(没有?不会吧)和一支笔(用作旋转轴),亲手做如下的几个旋转。

    首先确定手机的物体坐标系朝向,为了方便记忆,我们假设z轴与手机屏幕垂直(手机平放于桌面)指向上方,手机较短的一条边为x轴,较长的一条边为y轴(方向由手机尾部指向头部),物体坐标系的原点是手机左下角的顶点。(注意旋转顺序为zyx)

    绕z轴旋转任意角度(注意x和y轴也跟着一起旋转),再绕y轴旋转90°,再绕x轴旋转任意角度。通过多次尝试,你会发现一个共同点:z轴永远是水平的,通俗的说,手机永远也不会立起来!本来我们以为手机会指向任何方向,但实际上手机好像是被锁在桌面上,只能指向水平的某个方向,这个现象就称为万向锁。

     而如果绕y轴旋转不等于90°(1°也好89°也好),只要选择适当的绕x和z的角度,就可以让手机指向三维空间中的任何一个方向,手机是自由的,也就不会遇到万向锁现象。

 

三,游戏动画中遇到万向锁时会发生什么?

    之所以会出现万向锁现象,本质原因是,当第二次旋转角度为90°时,第三个轴就被转到了与第一个轴相同的方向,因此手机缺失了一个自由度(竖直方向的自由度缺失),只剩下第一个轴和第二个轴的自由度。而只有两个自由度意味着手机的运动被限制在了二维空间中,因此手机永远立不起来。

      在游戏中,当角色旋转的动画触发时,角色就会做一系列连续的旋转变换,每一个变换都要用一组欧拉角来表示,但是不可能吧每一个方位的欧拉角都存储起来,因此动画师定义了一系列关键帧,指定关键帧处角色的方位(用一组欧拉角描述),然后计算机根据时间t对这几组欧拉角进行插值,得到一系列欧拉角。

      如果pitch不是±90°,就不会出现万向锁现象,插值后的一系列欧拉角完全可以刻画出我们所期望的角色旋转路径。

      如果某个关键帧的pitch即绕第二个轴的旋转为90°,就会遇到万向锁,这时手机只能在水平面内旋转,如果动画师指定下一个关键帧手机的方位不是立起来的,没有任何问题,但如果指定的下一个关键帧的方位是立起来的,会出现什么情况呢?

      为了能有一个感性的认识,还是以手机为例,下面我指定了四个关键帧,四个关键帧处手机的方位分别用R0,R1,R2,R3四组欧拉角表示(逆时针为正方向,右手法则):

(注意R0处的物体坐标系与世界坐标系的指向是相同的,我假定z轴向上,x轴向右,y轴指向自己的胸口)

                  绕z轴旋转角度       绕y轴旋转角度      绕x轴旋转角度

R0:                     0                              0                       0

 

R1:                    90                             0                       0

 

R2:                    90                            -90                      0

 

R3:                     0                              0                       90

请先分别对手机做这四个变换,然后记住手机的这四个方位,想象一下你“期望”的连续的动画应该是什么样子的。

   简单说明如下:初始时刻,手机位于桌面上,屏幕朝上,手机头部指向你的胸口,然后,手机在桌面内逆时针旋转90°,知道手机头部指向右侧,然后手机的右边开始高起来,直到与桌面垂直,此时手机头部仍然指向右侧,由于R2的第二次旋转是90°,因此手机进入万向锁模式。然后手机应该背对着你,垂直于桌面站立起来,直到手机是竖直的背对你。   

      但实际情况是否是这样的呢?

      你可以自己尝试对这个四个方位角插值,然后进行旋转,看看得到的路径是否和上述我们所期望的相同。

      以下是我的尝试:

      求出R0 到R1以及R1到R2的插值,然后旋转,完全符合上面的路径。但是再求出R2到R3的几个插值后,旋转得到的路径与期望不符。比如这两个插值:

   z:60  y:60  x:30

   z:    45     y:45    x:45.

做这两个旋转,你会发现手机与桌面不垂直,也就是R2到R3的路径与期望的发生了偏移。这就是《3D数学基础:图形与游戏开发》中提到的“路径偏移”和“摄像机抖动”。

 

总结:如果动画师在某个关键帧处指定了会引发万向锁的方位,则下一个关键帧的方位一旦超出了万向锁的约束范围,则这两个关键帧之间的路径就会发生偏移,反映在角色动画上是旋转偏移,反映在镜头控制上就是镜头抖动。

 

要获得路径偏移的感性认识,可以参考这个视频:这个视频和我的描述有些不同,该视频使用一个称为万向节的奇怪装置解释的,而我是直接用的物体坐标系但路径偏移都是一样的。

http://v.youku.com/v_show/id_XNzkyOTIyMTI=.html

 

 

四,怎样解决万向锁这个问题?

出现这个问题的根本原因是在万向锁情况下对欧拉角的插值不是线性的,因此旋转路径发生偏移。

解决方法是:

将欧拉角转换为四元数,对四元数进行slerp即球面线性插值,再将这一系列四元数转换为对应的欧拉角,而后作用于角色。缺点是耗费一定的内存,但角色可以任意旋转,灵活度高。

这篇关于[转]游戏动画中欧拉角与万向锁的理解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/438374

相关文章

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

深入理解Redis大key的危害及解决方案

《深入理解Redis大key的危害及解决方案》本文主要介绍了深入理解Redis大key的危害及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、背景二、什么是大key三、大key评价标准四、大key 产生的原因与场景五、大key影响与危

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

最好用的WPF加载动画功能

《最好用的WPF加载动画功能》当开发应用程序时,提供良好的用户体验(UX)是至关重要的,加载动画作为一种有效的沟通工具,它不仅能告知用户系统正在工作,还能够通过视觉上的吸引力来增强整体用户体验,本文给... 目录前言需求分析高级用法综合案例总结最后前言当开发应用程序时,提供良好的用户体验(UX)是至关重要

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

Qt QWidget实现图片旋转动画

《QtQWidget实现图片旋转动画》这篇文章主要为大家详细介绍了如何使用了Qt和QWidget实现图片旋转动画效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、效果展示二、源码分享本例程通过QGraphicsView实现svg格式图片旋转。.hpjavascript

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。