iOS SceneKit粒子系统如何强制粒子朝向指定方向/姿态?
iOS SceneKit粒子系统如何强制粒子朝向指定方向/姿态?
我太懂你这种憋屈的感觉了——好不容易做出来的同心圆粒子,不管怎么调参数都死磕着X方向不放,旋转父节点、加动画控制器全不管用,SceneKit的文档又说得模棱两可。我之前做类似的径向扩散粒子时也踩过几乎一模一样的坑,其实问题出在你没抓住粒子初始朝向的控制逻辑,还有几个被忽略的关键属性。
先拆解下你之前的尝试为什么没用:
- 旋转父节点
pNode:粒子系统的朝向是基于自身发射坐标系的,而你用birthDirection = .surfaceNormal时,粒子的初始朝向默认和发射法线绑定,父节点旋转只会挪位置,改不了粒子自身的朝向逻辑 - 用
propertyControllers调rotationAxis和angle:一是你没给粒子一个明确的初始朝向基准,二是.free模式下粒子的初始朝向还是由birthOrientation(默认是.direction,即和运动方向绑定)决定的,动画相当于在错误的初始状态上做修改,自然看不到效果
正确的解决方案:固定粒子朝向的核心调整
要让粒子牢牢朝向Y轴向上(或任意指定方向),你只需要修改3个关键属性,再配合正确的初始朝向设置:
1. 切断粒子朝向和运动方向的绑定
默认birthOrientation = .direction会让粒子的初始朝向和运动方向(你这里是球体表面法线)完全绑定,所以第一步要把它改成.fixed,让粒子朝向不受运动方向影响:
particleSystem.birthOrientation = .fixed
2. 设置固定朝向模式
用orientationMode = .fixed让粒子始终固定在粒子系统的本地坐标系,不会随相机角度、粒子运动改变朝向:
particleSystem.orientationMode = .fixed
3. 给粒子设置目标朝向(Y轴向上)
SceneKit粒子的默认“正面”是Z轴正方向,要让它转向Y轴向上,我们需要给它一个绕X轴旋转90度的四元数(把Z轴转到Y轴的方向),用particleOrientation属性设置:
// 绕X轴旋转π/2(90度),让粒子正面朝向Y轴向上 particleSystem.particleOrientation = SCNQuaternionMakeRotation(Float.pi / 2, 1, 0, 0)
完整修改后的代码片段
把这些调整加到你的原代码里,最终的粒子系统部分是这样的:
let particleSystem = SCNParticleSystem() particleSystem.particleImage = UIImage(named: "circle.png") particleSystem.emitterShape = SCNSphere(radius: 0.01) particleSystem.birthLocation = .surface particleSystem.birthDirection = .surfaceNormal particleSystem.birthRate = 0.4 particleSystem.acceleration = SCNVector3(0, 0, 0) // 核心朝向控制代码 particleSystem.birthOrientation = .fixed particleSystem.orientationMode = .fixed particleSystem.particleOrientation = SCNQuaternionMakeRotation(Float.pi / 2, 1, 0, 0) // 粒子大小动画部分保持不变 let sizeController = SCNParticlePropertyController() let sizeAnimation = CAKeyframeAnimation(keyPath: "particleSize") sizeAnimation.values = [0.1, 0.4] sizeAnimation.keyTimes = [0.0, 1.0] sizeController.animation = sizeAnimation particleSystem.propertyControllers = [.size: sizeController] let pNode = SCNNode() pNode.addParticleSystem(particleSystem) rootNode.addChildNode(pNode)
额外说明:如果需要动态调整朝向
如果你之后想让粒子在生命周期内改变朝向(比如从X方向转到Y方向),可以用SCNParticlePropertyController给.rotation属性加动画,比如:
let rotationController = SCNParticlePropertyController() let rotationAnim = CAKeyframeAnimation(keyPath: "rotation") // 从初始X方向转到Y方向的四元数 let startRot = SCNQuaternionMakeRotation(0, 0, 0, 0) let endRot = SCNQuaternionMakeRotation(Float.pi / 2, 1, 0, 0) rotationAnim.values = [NSValue(scnQuaternion: startRot), NSValue(scnQuaternion: endRot)] rotationAnim.keyTimes = [0.0, 1.0] rotationController.animation = rotationAnim particleSystem.propertyControllers[.rotation] = rotationController
这种方式适合.free模式下的动态朝向变化,不过你现在的需求用固定模式就足够了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

