如果还没看前一篇,可以移驾看看:ios 3D引擎 SceneKit 开发(4) –关于旋转的几点问题(1)
上一篇我们用CABasicAnimation 来模拟了太阳-地球-月球的天体运动。其中月球绕太阳运动和月球绕地球运动都可以看做一个点绕另一个点作圆周运动。(当然现实中是椭圆运动,有远地点,近地点,这里我们看作圆周运动)
一个点绕另一个点作圆周运动,是不是很熟悉。对,就是我们之前学习的数学知识,这里完全可以用数学知识做。
相关数学知识点: 任意点a(x,y),绕一个坐标点b(rx0,ry0)逆时针旋转a角度后的新的坐标设为c(x0, y0),有公式:
x0= (x - rx0)*cos(a) - (y - ry0)*sin(a) + rx0 ;
y0= (x - rx0)*sin(a) + (y - ry0)*cos(a) + ry0 ;
OK,有这些数学基础,那我们就很好做了,我们让地月系统绕太阳转的效果用数学方法来实现。太阳(sunNode)是b点,地月系统(earthGroupNode)是a点,我们将地月系统添加到太阳里面:
[_sunNode addChildNode:_earthGroupNode];
那么相对于a点来说,b点的坐标就是(0,0),然后我们通过计算得到c点,让c点的坐标重新赋值给earthGroupNode 的 position 就可以了。代码如下:
// custom Action
float totalDuration = 10.0f; //10s 围绕地球转一圈
float duration = totalDuration/360; //每隔duration秒去执行一次
SCNAction *customAction = [SCNAction customActionWithDuration:duration actionBlock:^(SCNNode * _Nonnull node, CGFloat elapsedTime){
if(elapsedTime==duration){
SCNVector3 position = node.position;
float rx0 = 0; //原点为0
float ry0 = 0;
float angle = 1.0f/180*M_PI;
float x = (position.x - rx0)*cos(angle) - (position.z - ry0)*sin(angle) + rx0 ;
float z = (position.x - rx0)*sin(angle) + (position.z - ry0)*cos(angle) + ry0 ;
node.position = SCNVector3Make(x, node.position.y, z);
}
}];
SCNAction *repeatAction = [SCNAction repeatActionForever:customAction];
[_earthGroupNode runAction:repeatAction];
从上面可以看出我们用了SceneKit 的API SCNAction 去循环计算赋值,其实最主要的就是actionBlock 里面的代码,你也可以完全用线程sleep 和 NSTimer 去实现。
最终实现效果:
引出的问题:我们可以看到上面数学方法的局限性,y 轴的值一直没变,因为三个天体都处于X-Z这一平面,如果他们 y 值不一样,没有处于X-Z这一平面。即一个三维点绕着另一个三维点做圆周运动,数学方法该怎么实现?
demo 代码已上传到github
https://github.com/pzhtpf/SceneKitRoationDemo
时间: 2024-10-12 03:26:14