I would like to animate a certain color sequence in a SceneKit Particle System in code only. (Like one can do within the Particle System Editor in XCode.)
I was trying the following, and the App is crashing each time the Animation is attached to the particle system. The compiler does not complain, Xcode does not indicate any error within the syntax. (without the animation part, the particle system works fine)
func particleSystemTesting(shape: SCNGeometry) -> SCNParticleSystem {
let explosion = SCNParticleSystem(named: "explosion.scnp", inDirectory: nil)!
explosion.emitterShape = shape
explosion.birthLocation = .surface
explosion.birthDirection = .surfaceNormal
explosion.isAffectedByGravity = true
explosion.isLightingEnabled = false
explosion.loops = true
explosion.sortingMode = .none
explosion.isBlackPassEnabled = true
explosion.blendMode = .additive
explosion.particleColor = UIColor.white // using as default, should even not be required
// Animation Part
let animation = CABasicAnimation(keyPath: "particleColor")
animation.fromValue = UIColor.blue
animation.toValue = UIColor.red
animation.duration = 2.0
animation.isRemovedOnCompletion = true
explosion.addAnimation(animation, forKey: nil) // causing the crash
return explosion
}
This are the errors the console is printing out:
2020-08-23 18:25:53.281120+0200 MyTestApp[1684:892874] Metal GPU Frame Capture Enabled
2020-08-23 18:25:53.281349+0200 MyTestApp[1684:892874] Metal API Validation Enabled
2020-08-23 18:25:56.563208+0200 MyTestApp[1684:892874] -[SCNParticleSystem copyAnimationChannelForKeyPath:animation:]: unrecognized selector sent to instance 0x101041500
2020-08-23 18:25:56.564524+0200 MyTestApp[1684:892874] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SCNParticleSystem copyAnimationChannelForKeyPath:animation:]: unrecognized selector sent to instance 0x101041500'
*** First throw call stack:
(0x1998d5654 0x1995f7bcc 0x1997d9dd8 0x1998d97f8 0x1998db71c 0x1ade571f8 0x1ade55f24 0x1ade59268 0x1ade5af2c 0x1ade23d84 0x1adf18cf0 0x199852f2c 0x19984de20 0x19984e29c 0x19984dba8 0x1a39bd344 0x19d9893e4 0x100566384 0x1996d58f0)
libc++abi.dylib: terminating with uncaught exception of type NSException
After some more research and consulting apples docs reference it seems that my first approach was wrong, because that would affect all spawned particles at the same time.
BUT IT STILL DOES NOT WORK AS EXPECTED - all particles are gone/invisible on scene - otherwise no errors. this should change the colours of each particle over time. What is wrong?
func particleSystemTesting(shape: SCNGeometry) -> SCNParticleSystem {
let explosion = SCNParticleSystem(named: "explosion_testing.scnp", inDirectory: nil)!
// let explosion = SCNParticleSystem() // makes no difference
explosion.emitterShape = shape
explosion.birthLocation = .surface
explosion.birthDirection = .surfaceNormal
explosion.isAffectedByGravity = true
explosion.isLightingEnabled = false
explosion.loops = true
explosion.sortingMode = .none
explosion.isBlackPassEnabled = true
explosion.blendMode = .additive
// explosion.particleColor = UIColor.black
let red = UIColor.red
let green = UIColor.green
let blue = UIColor.blue
let yellow = UIColor.yellow
let color1 = SCNVector4(red.redValue, red.greenValue, red.blueValue, 1.0)
let color2 = SCNVector4(green.redValue, green.greenValue, green.blueValue, 1.0)
let color3 = SCNVector4(blue.redValue, blue.greenValue, blue.blueValue, 1.0)
let color4 = SCNVector4(yellow.redValue, yellow.greenValue, yellow.blueValue, 1.0)
let animation = CAKeyframeAnimation()
// animation.keyPath = "color" // has like no effect (?...)
animation.values = [color1,color2,color3,color4]
animation.keyTimes = [0, 0.333, 0.666, 1]
animation.duration = 2.0
animation.isAdditive = false // should overwrite default colours
animation.isRemovedOnCompletion = true
let colorController = SCNParticlePropertyController(animation: animation)
explosion.propertyControllers = [SCNParticleSystem.ParticleProperty.color: colorController]
return explosion
}
Apple Docs says this:
Apple Discussion
This property’s value is a four-component vector (an NSValue object containing an SCNVector4 value for particle property controllers, or an array of four float values for particle event or modifier blocks). The particle system’s particleColor and particleColorVariation properties determine the initial color for each particle.
I believe the documentation is wrong. Your animation values array should contain UIColor
objects.
animation.values = [UIColor.red, UIColor.green, UIColor.blue, UIColor.yellow]