如何在程序中实现对三维模型的旋转——探讨旋转过程中,程序所需要的变量与及计算原理
作者:KT
在程序中,通过鼠标旋转3D模型最常用的方法应该就是——轨迹球
参考了国外的博客文章和同济大学高等数学下册之后,终于能初步明白这种轨迹球的计算原理,
我看了一下高数,把一些公式的推导过程也列出来了。
本日志的文字,图片以及推导过程,都是我利用软件和参考书籍完成的,尽量力求正确了
如果发现错误存在,请联系本人
阅读可能有一定的难度,毕竟最近才开始写技术类文章。
模拟效果示意图——用两张图片模拟一下效果,本日志旨在理论上进行分析
如何在程序中实现对三维模型的旋转
第一 : 简单介绍
我们在显示器所看到的屏幕是二维平面(只有X和Y),因此鼠标的坐标也就有X和Y坐标,那么将屏幕看成是一个平面,在这个平面后面,虚构一个球体(轨迹球,3D模型就位于轨迹球之内),然后屏幕平面捕捉鼠标的坐标,然后将鼠标的坐标投影到球面上!(下图效果示意图)
——轨迹球旋转带动3D模型旋转?可以这样理解,不过具体解释,后面会有!
图中鼠标点击在屏幕平面时,必须将其投影至背后虚构的轨迹球球面上!
屏幕平面是二维坐标,而虚构的球体是三维坐标,很明显是不能将鼠标的坐标(X,Y)直接投影成三维坐标(X,Y,Z)
因此这个时候需要进行坐标维数的转换!
——二维坐标能够转换成三维坐标吗?答案是可以,虽然二维坐标只有(x,y),但是将二维坐标通过合理变化后,再利用x坐标值和y坐标值就能计算出z坐标值,后面我会写上详细的公式推导过程。
下图就是转化示意图,强调一点,这个是前视图的投影图来的,两个正方形都是屏幕平面的正面!
好,现在鼠标点击了屏幕平面,那么就必须利用一定的变化公式将这个点转变为三维坐标点!——即计算圆形中X和Y的值
注意三维图中的1和-1是相对数,代表1个单位,不是具体的值,因此三维图中的X和Y是相对值,即百分比!
Px、Py分别是鼠标的X坐标和Y坐标,这个在程序中是可以直接捕获得知数据的!
公式如下:
解释:因为三维图的中心点 (0,0) 在二维图中是(width/2,height/2),
px-width/2 就是该点在三维图中距离竖轴的距离,然后将该值除以width/2就能得出这段距离占1个单位的比例!——即 X 值!
那么Y的公式就是:
这样是错的!错的!
为什么,我们观察下,二维图中的Y轴,这个这里取的是Y的负半轴!所以Py应该是负值,
但是在三维图中,我们看到投影的点的坐标(x,y)是在[1,1]的正半轴区间内,y的值肯定是正数,所以要将上面计算出来的Y值取相反数!
正确的公式是:
一开始我也没有想明白,结果算错了,不过事后发现这里的推导还是很简单
如果大家还是不明白这一点的话,那么可以这样理解,首先利用
计算出来的y必定是负数,因为Py只能为负(二维坐标中,取的是Y的负半轴) ,好那么这样计算出来的投影点坐标应该是x为正,y为负,在[1,-1]区间内,那么这个点很明显与实际的投影点是关于中心横轴对称的,如图所示
那么计算错误的投影点Y 与 正确投影点的 Y 就应该是关于中心横轴对称的,互为相反数,因此对错误的Y取相反数就就能取得正确点的Y值,这样理解起来应该没问题了!
好了,现在我们已经拿到了投影点的X值和Y值了,那么正如前面所言,通过X和Y计算Z值!
在球体中 有一公式:
其中r是球体半径
公式推导:
首先需要预习一下向量的基础知识——翻起了高等数学 – -!
向量a , 向量 b , 向量 c
a+b=c 这个向量公式,大家应该都记得吧
那么开始进入球体公式推导
首先 a+b=c , c+e=f f 就是球面半径的向量 那么就是 f=c+e=a+b+e 求出向量的模的话,就是
其实 a的模就是x坐标值,b的模就是y坐标值,e就是z坐标值!
如果还是不懂话 ,直接用勾股定理吧 (x,y,z轴都是互相垂直的!)
好了,公式
Z坐标值计算公式:
因为球体半径r=1 所以,最终公式为
好啦,二维坐标转为三维坐标的计算完成, 得到了在轨迹球面上的投影点坐标(x,y,z)!
第三:点与点之间的旋转
示意图说明:鼠标投影点从v1处从移动到v2处,旋转轴的概念就等同于地球的地轴——这样说应该能明白了吧
如果要实现轨迹球旋转,就必须获得v1,v2,θ和旋转轴!
v1,v2可以用第二步中的坐标转换得到,
那么这里主要是计算出 θ和旋转轴
这里也是需要一些背景知识,其实大家都学过,还是向量
我借用书本上的例子来说几点——两向量的数量积! 两向量的向量积!
书本例子:——已经懂的可以跳过
同济大学高等数学第六版下册P13
设一物体在恒力F作用下沿直线从点M1移动到点M2,以S表示位移量M1M2,那么F所作的功的计算:
F看成是a向量
s看成是b向量 那么就有
a*b=|a| |b| cos(θ)
所以得到
好,这样我们就可以利用这个公式在轨迹图中计算θ值了
θ求出来了,那么旋转轴呢!
其实旋转轴
Axis=v1 * v2
因为对于向量a,向量b,向量c,
若c=a x b ,那么c就是必须与a,b都垂直的!
很明显旋转轴Axis是与v1和v2垂直的!满足于c=a x b!
所以Axis=v1 * v2
关于这点 具体解释 请见同济大学高等数学第六版下册P17
好,回答之前的问题
问:是轨迹球旋转带动3D模型旋转?
答:我现在的观点是,轨迹球是虚构存在的一个球,为了能够让程序在计算过程中获得一个球体曲面而虚构出来的立体图形,它的作用不是实现旋转,是为了将我们在程序(显示器屏幕平面)所点击的鼠标坐标转化为一个在球面上的坐标,我们看到的程序是一个平面,但是我们已经通过这个虚构的轨迹球将我们的操作球立体化了,那就相当于我们是在球面上操作着鼠标!然后计算出旋转所需数据,传递给3D模型,使其发生旋转变化!轨迹球就是一个为了满足计算而提供曲面的虚构立体图形!
这里我想用一句简单的话话概括这篇日志的重点
——虽然我们看到的是一个平面,但是我们在这平面背后操作的是一个立体图形!
——————————————————————————————
好了,现在能够计算出v1,v2,θ和旋转轴,这个四个东西已经能够满足一般的旋转动画的变量需求了,一般的3D模型旋转动画程序都是需要这四个变量——当然还有一些很强劲的dll提供的接口已经是很人性化了,只将二维的鼠标坐标跟3D模型传进去函数即可。虽然我弄了这些这些公式推导,但在实际生活中,我也会试着去找别人写好高级类库来完成工作,因为这个理论的推导用的是球体,忽略了3D模型的具体外在形式,现实生活中的模型,不可能那么完美的嵌入到球体中,有可能是需要椭圆体,这个时候利用上面的推导会出现很严重的快速转移错误——因为高度变窄,鼠标稍微移动就能产生大幅度的旋转,这种旋转是快速而错误的!
这仅仅是一个问题,还有各种变焦,摄像机角度更换的更深层次的