起义时刻怎么无限发大或缩放视角

在本系列第一篇介绍过鼠标按键嘚功能如下。

  • 左键拖拽 - 旋转魔方
  • 右键拖拽 - 变换视角

今天研究一下如何实现后面两个功能用到的技术主要是Arcball,Arcball是实现Model-View-Camera的重要技术这里嘚旋转基于Quaternion(四元数)来实现,当然也可以通过欧拉角来实现但是欧拉角的旋转不够平滑。先看一下Model-View-Camera的效果如下,这个gif效果图是用LICEcap录淛的帧率有些慢,略有卡顿现象大家可以下载文末的可执行文件查看更加平滑的效果。

由上面的动画可以看到通过用户按下并拖拽鼠标右键即可以旋转视角(表面上看是魔方在旋转,但实际上是camera在旋转相对运动而已)。为了研究这个功能是如何实现的我们可以将鼠标右键拖拽这个过程分解一下。

  • 按下鼠标右键(此时鼠标的位置是P1)
  • 拖拽右键(此时鼠标的位置是P2注意P2是随拖拽实时变化的)
  • 抬起鼠標右键(停止旋转)

为了实现上面的功能,我们在屏幕上虚拟出一个球体来将P1和P2映射到这个球体,再从球心到P1和P2连线构成两个向量有叻这两个向量就可以求出旋转轴及旋转角度了,这个虚拟的球体就是Arcball了,如下图

在上图中P1和P2的夹角就是旋转角度,N则是旋转轴旋转角度可以通过P1和P2的点积来实现,旋转轴可以通过P1和P2的叉积来实现稍后详述,下面看看如何将屏幕上的点映射到球体上这是实现Arcball的关键步骤。直观一点的想法可以把屏幕看成一个矩形纹理,球体看做一个模型所以将屏幕坐标映射到球体坐标的过程实际上相当于将这个矩形纹理贴图到球体上。需要注意的是我们这里只用到半个球体(如果屏幕将球体一份为二的话)。

看代码顾名思义,这个函数完成屏幕坐标到球体坐标(单位向量)的转换两个输入参数分别是鼠标按下时屏幕的X,Y坐标

4-5两行代码将屏幕坐标映射到球体坐标的范围,泹此时还只是xy两个分量所以后续的代码都是计算z坐标并单位化的。这里radius_是球体的半径为了方便计算,通常设置为1

10-15行,如果xy的平方和夶于1此时该点恰好位于半球球的边缘,所以令z=0

17行如果xy平方和小于1,说明该点不位于半球边缘计算z的值。

19行返回球体坐标对应的向量(已经单位化)

关于这个函数更加详细的解释,看以看看我的另一篇随笔。

这里我们用四元组来表示旋转一个四元组包含四个分量x, y, z, w。假设一个旋转的旋转轴是axis旋转角度是theta。那么对应的四元组q如下

有了上面的公式,我们就可以根据旋转轴和旋转角度来构造四元组了下面的函数就是用来做这件事的,两个参数分别是旋转的起始向量和结束向量这两个向量是由前面的ScreenToVector函数生成的。

第7,8两行代码计算旋轉轴用的是叉积公式,两个向量P1和P2的叉积生成第三个向量N且N垂直于P1和P2。

第11,12行构造四元组并单位化。需要注意的是旋转轴部分并没有嚴格按照上面的四元组公式因为旋转轴是一个向量,而同一个方向可以有多种表示方法比如(1,2,3)和(2,4,6)表示的是同一个方向向量。

当鼠标右键按下时设置frame_need_update_为true,这个向量表示鼠标移动时是否有拖拽发生因为Windows并没有对应鼠标拖拽的消息,所以要通过两个方面来判断一昰鼠标按下了,二是鼠标移动了同时满足这两个条件才表示拖拽发生了。调用ArcBall.OnBegin函数这个函数会判断当前的鼠标位置是否位于窗口客户區内,如果在客户区外则不做相应如果鼠标在窗口客户区内,还要记录当前鼠标的位置并生成球体向量用于后续计算。

当鼠标移动时调用ArcBall.OnMove(),这个函数首先求取鼠标当前位置并生成球体向量,在根据上一次保存的球体向量计算出旋转增量对应的四元组

缩放使用鼠标滾轮来完成,在WM_MOUSEWHEEL消息HIWORD里面存放的是鼠标滚轮的增量。获取这个增量并

在Camera类的OnFrameMove中判断是否有滚轮滚动,并做响应的处理代码如下。

这個if语句会根据滚轮的增量计算radius_并将radius_限制在范围[min_radius_, max_radius_]内,防止模型过大或者过小radius_变量稍后会用来计算眼睛到视点的距离,通过改变这个距离嘚值达到模型放大和缩小的效果实际上模型并没有真正被缩放,只是观察的距离变了而已这样就会产生近大远小的效果了。下面的代碼用来计算眼睛的位置

Camera类是Arcball的使用者,里面的OnFrameMove函数每一帧都会被调用该函数负责缩放和旋转,并生成新的View Matrix

第4行首先判断是否有拖拽,如果没有拖拽动作则不必更新视角直接返回。

第6行将是否拖拽标志设置为false因为能走到这一行表示有拖拽。

第8-15行处理鼠标滚轮动作並确保camera的radius在控制范围内,这样魔方不至于太小或者太大

第18行将滚轮的旋转增量清0,因为增量不累加每个frame计算一次,下一个frame重新计算

苐21-22行求出旋转矩阵的逆矩阵,因为如果要达到同样的视角模型和camera的旋转方向刚好相反。可以这样理解如果想看魔方的背面,我们可以將魔方旋转180度这相当于旋转模型,也可以固定魔方走到魔方的背面去看,这就是旋转camera了

之前有几个网友提出公布源代码,当时由于玳码比较混乱所以没有公布,我花了几个星期的时间将所有代码重新整理了一遍,现在基本上可以看了但是还有很多细节需要打磨。昨晚上传到了github上欢迎fork,如果不熟悉github也可以在博客园本地下载。

编译源代码需要安装DirectX SDK推荐大家使用Microsoft DirectX SDK (June 2010),这是最新的SDK当然也是最后一個。大家可以自己编译试着玩玩如有问题,欢迎留言讨论

如果不想看代码,可以下载下面的可执行文件试玩这个版本修复了之前几位网友发现的几个bug,还是那句话欢迎大家继续找毛病。

这个Demo刚刚上传到github还有很多功能需要完善,由于个人精力有限如果哪位网友有興趣,可以和我一起完成那就太好了,期待你的加入!稍后将这个Demo升级编写DirectX10及DirectX11版本的RubikCube,也算是一个练手的过程吧欢迎继续关注!

我在玩遭遇战的时候突然发现在那个时候我的视窗可以无限放大和缩小甚至可以囊括整个地图或者看清楚维和步兵的枪和盾牌,后来就不行了这是怎么回事?求解!┅帮神经病和白痴不要出... 我在玩遭遇战的时候突然发现在那个时候我的视窗可以无限放大和缩小甚至可以囊括整个地图或者看清楚维和步兵的枪和盾牌,后来就不行了这是怎么回事?求解!

其实正常的红警是不会出现这种情况的而你的可能是bug,至于后来又不行了那鈳能是由于你安装了什么东西(可能是补丁什么)总之有修改权限的东西,你只需找到把它还原就可以了

你对这个回答的评价是


玩过它嘚教学关卡就知道了,这是红警三的创新之处上推下划滑鼠键是放大缩小视窗,按住鼠标并移动还可改变视角

你对这个回答的评价是?


有一种挂可以这样你说这是不是BUG啊~~

你对这个回答的评价是?


你对这个回答的评价是

下载百度知道APP,抢鲜体验

使用百度知道APP立即抢鮮体验。你的手机镜头里或许有别人想知道的答案

求助电脑怎么调整让视角变的哽大看的更多,缩放等级调最小了分辨率最高了,也全屏了还有什么方法吗


我要回帖

 

随机推荐