2016-02-14 18 views
6

Recentemente ho chiesto un question che aveva una risposta piuttosto ovvia. Sto ancora lavorando allo stesso progetto e mi sto imbattendo in un altro problema. Devo implementare la logica per frame e il protocollo SCNSceneRendererDelegate ha funzionato perfettamente su iOS, ma su OSX, la funzione renderer non sta funzionando. Ho creato un piccolo progetto di esempio per illustrare il mio problema. Si compone di un kit di scena vista in storyboard e seguente codice nella classe ViewController:SceneKit SCNSceneRendererDelegate - funzione di rendering non chiamata

import Cocoa 
import SceneKit 

class ViewController: NSViewController, SCNSceneRendererDelegate { 

    @IBOutlet weak var sceneView: SCNView! 

    let cubeNode = SCNNode() 

    override func viewDidLoad() { 

     super.viewDidLoad() 

     let scene = SCNScene() 

     let sphere = SCNSphere(radius: 0.1) 
     sphere.firstMaterial!.diffuse.contents = NSColor.yellowColor() 
     let sphereNode = SCNNode(geometry: sphere) 
     scene.rootNode.addChildNode(sphereNode) 

     let cube = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0) 
     cube.firstMaterial!.diffuse.contents = NSColor.greenColor() 
     cubeNode.geometry = cube 
     cubeNode.position = SCNVector3(1,0,0) 
     scene.rootNode.addChildNode(cubeNode) 

     let cameraNode = SCNNode() 
     cameraNode.camera = SCNCamera() 
     cameraNode.position = SCNVector3(2, 1, 2) 
     let constraint = SCNLookAtConstraint(target: cubeNode) 
     cameraNode.constraints = [constraint] 
     scene.rootNode.addChildNode(cameraNode) 

     sceneView.scene = scene 
     sceneView.backgroundColor = NSColor(red: 0.5, green: 0, blue: 0.3, alpha: 1) 
     sceneView.allowsCameraControl = true 

     sceneView.delegate = self 
     sceneView.playing = true 

    } 

    func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) { 
     cubeNode.position.x += 0.1 
    } 
} 

Tutto quello che voglio è quello di spostare sostanzialmente il cubo con ogni fotogramma. Ma non succede nulla. La cosa strana è che quando imposto lo sceneView.allowsCameraControl su true, la funzione renderer viene chiamata ogni volta che clicco o trascino sullo schermo (il che ha senso perché è necessario aggiornare la vista in base agli angoli della telecamera). Ma vorrei che fosse chiamato ogni frame.

C'è un errore che non vedo o si tratta di un bug nel mio Xcode?

Edit: Ho provato seguendo le istruzioni riportate nella risposta qui sotto e ora hanno il seguente codice per la ViewController:

import Cocoa 
import SceneKit 

class ViewController: NSViewController { 

    @IBOutlet weak var sceneView: SCNView! 
    let scene = MyScene(create: true) 

    override func viewDidLoad() { 

     super.viewDidLoad() 

     sceneView.scene = scene 
     sceneView.backgroundColor = NSColor(red: 0.5, green: 0, blue: 0.3, alpha: 1) 
     sceneView.allowsCameraControl = true 

     sceneView.delegate = scene 
     sceneView.playing = true 

    } 

} 

e una classe myscene:

import Foundation 
import SceneKit 

final class MyScene: SCNScene, SCNSceneRendererDelegate { 

    let cubeNode = SCNNode() 

    convenience init(create: Bool) { 
     self.init() 

     let sphere = SCNSphere(radius: 0.1) 
     sphere.firstMaterial!.diffuse.contents = NSColor.yellowColor() 
     let sphereNode = SCNNode(geometry: sphere) 
     rootNode.addChildNode(sphereNode) 

     let cube = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0) 
     cube.firstMaterial!.diffuse.contents = NSColor.greenColor() 
     cubeNode.geometry = cube 
     cubeNode.position = SCNVector3(1,0,0) 
     rootNode.addChildNode(cubeNode) 

     let cameraNode = SCNNode() 
     cameraNode.camera = SCNCamera() 
     cameraNode.position = SCNVector3(2, 1, 2) 
     let constraint = SCNLookAtConstraint(target: cubeNode) 
     cameraNode.constraints = [constraint] 

     rootNode.addChildNode(cameraNode) 
    } 

    @objc func renderer(aRenderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) { 
     cubeNode.position.x += 0.01 
    } 
} 

Tuttavia, è continua a non funzionare. Che cosa sto facendo di sbagliato?

Modifica: impostazione sceneView.loops = true risolve il problema descritto

risposta

3

ho il sospetto che la risposta dipende su che cosa querent intende per "ogni fotogramma". Querent dovrebbe probabilmente chiarirlo, ma proverò a rispondere comunque perché sono così.

L'interpretazione più semplice è probabilmente "ogni fotogramma che dovrebbe comunque renderlo", ma sembra improbabile che sia ciò che si desidera a meno che il cubo non sia concepito come un tipo di monitor dell'attività per il renderer, il che non sembra probabile; ci sono approcci molto migliori a questo.

È possibile eseguire il rendering di Querent ripetutamente mentre la proprietà playing della vista è SÌ. In tal caso, forse la risposta è semplice come impostare la proprietà loops della vista su SÌ. Recentemente ho risolto un problema per il quale volevo che il rendering si verificasse mentre si teneva premuto un tasto della tastiera. (Avevo notato che l'impostazione di riproduzione a SÌ induceva una singola chiamata al mio delegato.)

+0

Esattamente! Ho capito anche io, ma ho dimenticato di aggiornare la mia risposta. – Nico

+0

In tal caso, sembra che questa sia la risposta che dovrebbe essere accettata. –

-2

Prova questo ... inserire il codice in una classe di scena, invece - mantenere il controller della vista pulita.

final class MySCNScene:SCNScene, SCNSceneRendererDelegate 
{ 
    @objc func renderer(aRenderer:SCNSceneRenderer, updateAtTime time:NSTimeInterval) 
    { 
    } 
} 

impostare anche delegato della vista alla scena:

mySCNView .delegate = mySCNScene

+0

Grazie per il suggerimento, ma non sono sicuro di come collegarlo con ViewController e Storyboard ... Potresti spiegare un po 'di più? – Nico

+0

Lo storyboard e il controller di visualizzazione non hanno alcun ruolo in questo, è tutto su SCNView e SCNScene. SCNView ha una proprietà di scena, basta impostare SCNScene su di esso. – StackUnderflow

+0

Ho modificato la mia domanda con quello che penso sia la tua soluzione ma non funziona ancora. Ti ho frainteso? – Nico

7

Non capisco che cosa sta causando il problema, ma sono stato in grado di replicare. Ho preso a lavorare, anche se, con l'aggiunta di un insignificante SCNAction:

let dummyAction = SCNAction.scaleBy(1.0, duration: 1.0) 
let repeatAction = SCNAction.repeatActionForever(dummyAction) 
cubeNode.runAction(repeatAction) 

Il render fuochi anello solo se la scena è "giocare" (vedi SKScene becomes unresponsive while being idle). Mi aspetto che l'impostazione

sceneView.isPlaying = true 

(come si sta già facendo) sarebbe sufficiente per attivare il rendering di richiamate.

Il codice che ho sopra non è una soluzione. È un brutto trucco per aggirare il tuo problema e permetterti di andare avanti con la vita.

+1

Grazie, presenterò un rapporto! – Nico

+1

Non vedo come questa potrebbe essere la "soluzione" aggiungendo una SCNAction priva di significato ... sul serio? Le persone si confonderanno alla ricerca di risposte. – StackUnderflow

+1

@Nico Se si archivia un report, è importante aggiornare questo thread. Ma dubito che accetteranno il tuo rapporto come un insetto. – StackUnderflow

3

Per chiunque abbia ancora problemi, l'impostazione del delegato e la riproduzione delle variabili funzioneranno.

sceneView.delegate = self 
sceneView.isPlaying = true 
+0

L'avevo già fatto, ma come sottolineato da Integer Poet, sceneView.loops = true risolve il problema. – Nico

Problemi correlati