【qml-11】Quick3D实现机器人欧拉旋转、拖动视角
背景:
上一篇记录了使用Quick3D实现了一个晶圆机器人示教器的展示。更多是从零开始的实现思路。在制作过程中,有些问题比较头疼,甚至是有悖于人类的正常思维的。所以本次主要记录曾有疑问的要点。
因为我接触这些不超过三天,所以谈不上学术性,只能是个人记录。看官若要得到权威理论,还是要看正规著作。
坐标轴:
默认坐标轴是眼睛面向屏幕而言:x轴向右,y轴向上,z轴向外。
我得到模型默认也是这样的。
机器人组合完也是这样的:
上图已经加上颜色了。
所以组合时一定要记着这个规律。最后要实现最终想要的效果,是一定要进行整体旋转的。
用右手表示xyz轴时,大拇指x,食指y,中指z。
旋转方向:
旋转的概念是以坐标轴为基础而言的,以中学平面解析几何为例,x轴向右,y轴向上。假设以原点为轴,画一条直线与x轴夹角30度。
这种再常见不过的概念,在3d世界里叫围绕z轴转30度。
因为只看xy平面时,z轴正好是垂直屏幕向外的,也就是冲着人类眼睛的。
所谓对那个轴旋转,就是围绕这个轴旋转。这个轴的正数方向正对眼睛,角度是以平面几何的方向计算的,也就是逆时针方向是增大,顺时针是减小。
其实就是物理电学中的右手定则,大拇指指向坐标轴正数方向,四指弯曲指向角度增长方向。
欧拉旋转eulerRotation:
欧拉旋转的单位是角度,也是通常推荐使用的方式。还有四元旋转,我试过意义不大,实际开发中欧拉旋转即可。
三维空间旋转都是围绕坐标轴而言的,可以一次性指定三个轴的旋转角度:
eulerRotation:Qt.vector3d(40, 40, 40)
也可以分别指定:
eulerRotation.x:30
eulerRotation.y:60
eulerRotation.z:90
Qt.vector3d这个函数很有用,通常用于为三个轴指定参数。
重要的是,欧拉旋转是有顺序的,qt手册里提到顺序概念,是zxy,但我试出来是yxz。亦即如果要依次围绕xyz轴旋转,得按照这个顺序,否则就万向节锁死。啥叫锁死?实践中就是比如:
起始默认:x轴向右,y轴向上,z轴垂直屏幕向外。
我们希望某物体旋转时,xyz轴的三维空间能够保持。但实际是得按顺序逐个转,如果不按顺序,后转的轴就会保持上次的方向,不跟随三维空间一起转。
以上面的机器人为例,先看正确顺序yxz:
上面依次旋转90度,自己一边比划一边看,是正确的。
如果按照一个错误的顺序,比如xyz或者xzy再试试:
x之后,y旋转时,显然y还是初始方向,以向上为基准转的右手定则。后面z向下本来是对的,但因为前面y错了,所以z旋转又把y那次转回来了,最终还是错。
x之后,z旋转时,z向下是对的,因为z本来就该在x之后。再y旋转时,还是等于y向上做的右手定则,最终错。
所以我是尝试了很多次才明确,旋转的顺序就是yxz。
至于顺序影响结果的原因,AI说与矩阵算法有关,如果不是专门搞这个的,可以不深究,知道这个特性即可。
单位分离:
上述欧拉旋转的顺序问题,前提是针对一个3d单位进行xyz旋转。
实际制作时,机器人各关节都是独立的Model(node),机器人整体也是大环境的子node。
所以无论大场景怎么错,机器人再转也是对的,因为它是独立的单位。
会写程序的朋友已经想到,咱就使用node套壳不就行了,三层壳,分别管xyz轴。实际不对。因为咱们希望无论转哪个轴,另外两个轴的方向要随着三维空间联动。分层的话都是绝对方向,等于人为“万向节锁死”了。如果说非要进行某种计算才满足要求,我人为研究方向就错了,就不该较这个真,因为做项目需要效率,在一个问题上坑挖得太深,不是工程思维。搞不好都没信心继续了。
但分层控制有时候又是必须的,比如局部旋转,它本身就是相对的,而且只转一个轴,升降属于平移,不影响,做关节最合适了。
三维观察:
上面说了那么多旋转的问题,其实最初我想要物体任意顺序转都是对的,就是想实现三维空间上各角度观察物体。最好能用鼠标拖拽改变视角。
曾经想过转相机,思路就不对,因为所谓旋转都是对自己而言,直接转不行。
最终发现很简单,给View3D加个子节点即可:
WasdController {controlledObject: scenexSpeed: -0.1ySpeed: -0.1}
这个WasdController默认就可以拖拽转视角,但也是相对于被控制的那个node本身的,所以人眼看起来正好相反。
比如鼠标往上拖拽:一般我们是想把物体底面翻上来,但默认正好相反,物体会绕x轴正转(逆时针角度增加),所以等于是把顶面翻下来了。
如果鼠标往左拖拽:一般我们想要把右面翻出来看,但实际物体会绕y轴正转(逆时针角度增加),所以等于是把左面翻出来了。
所以必须要把xy反过来,翻过手册,有bool型反转属性,试过不行。最后尝试把速度设为default值取反,成功了。
但这种成功是局部的,如果物体把脸扭过来,人眼还是觉得是别扭的,做好了自己试试就知道了。相对值和绝对值的作用,想要完全用拖拽实现,难顾周全。以后有空再尝试更好的做法。
可以肯定的说一种有效的方法,不用拖拽,用两个slider,一个控制场景的x轴旋转(相当于纵向翻转),一个控制机器人原地转圈(相当于横向翻转)。
总结:
使用欧拉旋转实现的各关节运动。
使用WasdController实现的拖拽视角。场景x轴控制纵向翻转,机器人z轴控制横向旋转。
使用定义属性传递数据驱动模型运动。
反之,如果用鼠标操作关节产生数据,也是可以发给设备驱动真实的机器人的。但仔细想过意义不大,还不如界面控件或者机械手柄高效。
有关quick3d的应用目前就会这些,以后有需要再继续。
本文完。