SCNParticleSystem: animazione della proprietà "particleColor" nel codice

Aug 24 2020

Vorrei animare una determinata sequenza di colori in un sistema di particelle SceneKit solo nel codice. (Come si può fare all'interno dell'editor del sistema di particelle in XCode.)

Stavo provando quanto segue e l'app si arresta in modo anomalo ogni volta che l'animazione è collegata al sistema di particelle. Il compilatore non si lamenta, Xcode non indica alcun errore all'interno della sintassi. (senza la parte di animazione, il sistema particellare funziona bene)

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
    
}

Questi sono gli errori che la console sta stampando:

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

Dopo qualche altra ricerca e consultando i riferimenti dei documenti sulle mele , sembra che il mio primo approccio fosse sbagliato, perché ciò avrebbe influenzato tutte le particelle generate contemporaneamente.

MA ANCORA NON FUNZIONA COME PREVISTO - tutte le particelle sono sparite/invisibili sulla scena - altrimenti nessun errore. questo dovrebbe cambiare i colori di ogni particella nel tempo. Che c'è?

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 dice questo:

Discussione Apple

Il valore di questa proprietà è un vettore a quattro componenti (un oggetto NSValue contenente un valore SCNVector4 per i controller di proprietà delle particelle o un array di quattro valori float per i blocchi di eventi o modificatori di particelle). Le proprietà ParticleColor e ParticleColorVariation del sistema particellare determinano il colore iniziale di ogni particella.

Risposte

1 JamesP Aug 28 2020 at 20:19

Credo che la documentazione sia sbagliata. L'array dei valori dell'animazione dovrebbe contenere UIColoroggetti.

animation.values = [UIColor.red, UIColor.green, UIColor.blue, UIColor.yellow]
Voltan Aug 24 2020 at 22:20

Problema interessante Questo:https://developer.apple.com/documentation/scenekit/animation/animating_scenekit_contentmostra una chiamata simile con una SCNTransaction, quindi sembra che quello che stai facendo "dovrebbe" funzionare. Tuttavia, non era un componente del sistema SCNParticle. Le particelle possono essere un po' complicate con cui lavorare. Non sono bravo con le cose del selettore, quindi non posso davvero dirlo solo guardando il codice.

partitionColorVaration - il vettore randomizza il colore specificato. Non suona esattamente come quello che vuoi fare, ma potrebbe avvicinarti: il vettore specifica gli intervalli (tonalità, saturazione, luminosità, alfa) in quell'ordine.