2015-03-26 19 views
5

Ben SceneKit ile test edilmiştir iPhone 5 fakat normal üzerinde "kalmış", bu yüzden bir sanal gerçeklik testi uygulaması yapmaya karar verdi. Verileri cihaz hareketinden alırdım ve ardından verilere göre kamera açılarını değiştirirdim. IPhone 6'da test ediyordum, yani sorun değil. IPhone 5 ve bir arkadaşınızın iPhone 5S'de çalıştırdığımda garip olan şey, kameranın dönmesi için biraz gecikme olacak, iPhone 6'da ise çok farklı. Xcode'taki FPS, her iki cihazda da 60 FPS civarında kalıyor, bazı testler ekledim ve her iki cihazda da hareket verileri 60 Hz civarında geliyor. Kayboldum. https://github.com/stevenjs/VR-iOS-ExperimentSceneKit ve CoreMotion iPhone 6

Mümkünse, ben & yapıştırılan kopya olmaya hazır değil sadece kod düzeltmek için bazı ipuçları istiyorum:

kodu için taban bu proje. Öğrenmek istiyorum.

Ben sözlerle de bunu açıklayamam, bu yüzden neler olduğunu göstermek için bazı videolar kaydettik:

iPhone 6: https://www.youtube.com/watch?v=pdyTEwvsR1I

iPhone 5: Burada https://www.youtube.com/watch?v=MlDdKtHkrYo

oluyor Kod:

// Create Scene 
    var scene = SCNScene() 
    scnView.scene = scene 
    //scnView.autoenablesDefaultLighting = true 

    //Add camera to scene. 
    let camera = SCNCamera() 
    camera.xFov = 45 
    camera.yFov = 45 

    let camerasNode = SCNNode() 
    camerasNode.camera = camera 
    camerasNode.position = SCNVector3(x: 0, y: 0, z: 0) 
    // The user will be holding their device up (i.e. 90 degrees roll from a flat orientation) 
    // so roll the camera by -90 degrees to orient the view correctly 
    // otherwise the object will be created "below" the user 
    camerasNode.eulerAngles = SCNVector3Make(degreesToRadians(-90.0), 0, 0) 

    let cameraRollNode = SCNNode() 
    cameraRollNode.addChildNode(camerasNode) 

    let cameraPitchNode = SCNNode() 
    cameraPitchNode.addChildNode(cameraRollNode) 

    let cameraYawNode = SCNNode() 
    cameraYawNode.addChildNode(cameraPitchNode) 

    scene.rootNode.addChildNode(cameraYawNode) 

    scnView.pointOfView = camerasNode 

    // Ambient Light 
    let ambientLight = SCNLight() 
    ambientLight.type = SCNLightTypeAmbient 
    ambientLight.color = UIColor(white: 0.1, alpha: 1.0) 
    let ambientLightNode = SCNNode() 
    ambientLightNode.light = ambientLight 
    scene.rootNode.addChildNode(ambientLightNode) 

    // Omni Light 
    let diffuseLight = SCNLight() 
    diffuseLight.type = SCNLightTypeOmni 
    diffuseLight.color = UIColor(white: 1.0, alpha: 1.0) 
    let diffuseLightNode = SCNNode() 
    diffuseLightNode.light = diffuseLight 
    diffuseLightNode.position = SCNVector3(x: -30, y: 30, z: 50) 
    scene.rootNode.addChildNode(diffuseLightNode) 

      let material = SCNMaterial() 
    material.diffuse.contents = UIColor.redColor() 
    material.locksAmbientWithDiffuse = true 
    let material2 = SCNMaterial() 
    material2.diffuse.contents = UIColor.whiteColor() 
    material2.locksAmbientWithDiffuse = true 
    let material3 = SCNMaterial() 
    material3.diffuse.contents = UIColor.blueColor() 
    material3.locksAmbientWithDiffuse = true 
    let material4 = SCNMaterial() 
    material4.diffuse.contents = UIColor.purpleColor() 
    material4.locksAmbientWithDiffuse = true 
    let material5 = SCNMaterial() 
    material5.diffuse.contents = UIColor.yellowColor() 
    material5.locksAmbientWithDiffuse = true 
    let material6 = SCNMaterial() 
    material6.diffuse.contents = UIColor.orangeColor() 
    material6.locksAmbientWithDiffuse = true 


    //Create the box 
    let baseBox = SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0) 

    baseBox.materials = [material, material2, material3, material4, material5, material6] 
    let boxNode = SCNNode(geometry: baseBox) 
    boxNode.position = SCNVector3(x: 0, y: 3, z: -10) 
    scene.rootNode.addChildNode(boxNode) 


    // Respond to user head movement 
    motionManager = CMMotionManager() 
    motionManager?.deviceMotionUpdateInterval = 1.0/60.0 

    motionManager?.startDeviceMotionUpdatesUsingReferenceFrame(CMAttitudeReferenceFrameXArbitraryZVertical, 
     toQueue: NSOperationQueue.mainQueue(), 
     withHandler: { (motion: CMDeviceMotion!, error: NSError!) -> Void in 
      self.counter++ 
      let currentAttitude = motion.attitude 
      let roll = Float(currentAttitude.roll) 
      let pitch = Float(currentAttitude.pitch) 
      let yaw = Float(currentAttitude.yaw) 

      //only working at 60FPS on iPhone 6... WHY 

      //according to documentation, SCNVector3 from a node is, (pitch, yaw, node) 
      cameraRollNode.eulerAngles = SCNVector3Make(0.0, 0.0, -roll) 
      cameraPitchNode.eulerAngles = SCNVector3Make(pitch, 0.0, 0.0) 
      cameraYawNode.eulerAngles = SCNVector3Make(0.0, yaw, 0.0) 
    }) 
+0

İyi soru ... bilmiyorum. Bir tahminde bulunmak için, hareket güncelleme kuyruğu ile SCN oluşturma döngüsü arasında senkronizasyon yapılması gereken bir şey olduğunu söyleyebilirim. Bağımsız olarak gerçekleşen ve aralarında iletişim kurmaya çalışan bu iki 60Hz'lik işlemden ziyade, şeyleri tek bir 60Hz döngüsünde birleştirmek isteyebilirsiniz - yani, sahnenizdeki render verisi "update" yöntemindeki hareket verileri için anket. (Bkz. [CMMotionManager belgesindeki genel bakış] (https://developer.apple.com/library/ios/documentation/CoreMotion/Reference/CMMotionManager_Class/index.html).) – rickster

+0

@rickster Teşekkürler! Bunu söylediğin gibi uygulamaya çalışıyorum, şu anda ViewController benim delege, ama temsilci yöntemi 'render (aRenderer: SCNSceneRenderer, updateAtTime: NSTimeInterval)' sadece üç kez denir. Belki de render metodu, çerçeveleri güncelleyen tek şeydir? Bu tür bir kısa devre kendisi mi? –

+0

Yup, yöntemin sonuna 'sceneView.playing = true' eklediğimde, bu sahne setini sonsuza kadar devam ettirmeye zorladı. Bunu yapmanın doğru yolu nedir acaba? –

cevap

11

Bu sadece bir önseziydi, ama sanırım doğru çıktı, bu yüzden resmi yapalım! CoreMotion güncelleme kuyruğuna ve SceneKit render döngü -

Senin sorunun iki 60Hz zamanlayıcılar ana iş parçacığı üzerinde süre çekişen döngüler/vardır gibi görünüyor. Etkili ki sen CoreMotion güncelleme işleyicisinde SceneKit durumunu kuruyorsun, birinden diğerine iletişim ve SceneKit döngü işlemek umuyoruz aynı karede onu alır.

(Donanım farklılığı, iPhone 6'nın zamanlamanın tamamlanabileceği kadar yeterli performans yüküne sahip olduğunu ve eski donanımın da olmadığından şüpheleniyorum. Bu nedenle SceneKit, bir çerçeve veya iki arka plandaki model konumlarını alıyor hareket verileri.)

Bunun yerine, aynı 60Hz döngü içinde her şeyi yapmak. (Gerçekten de bu, diğer 60Hz olay kaynağınız CoreMotion veya başka bir şey olsun, bir oyun motorunda veya benzer bir gerçek zamanlı işleyicide olsun, iyi bir genel öneridir, render yapmak için hedef çerçevenin oluşturulmasına izin vermelisiniz.)

Bu, hareket verileri için yoklama olmanız gerektiği anlamına gelir, size itilmeden değil - yalnızca, oluşturduğunuz çerçevenin zaman damgasından itibaren hareket durumunu dikkate alırsınız. Bir çerçeveyi düşürdüyseniz son birkaç örnek. CoreMotion en deviceMotion sizin renderer:updateAtTime: yönteminde okuma ve orada modeli rotasyonlar set, bir scene renderer delegate ile SceneKit render döngüye Hook. Hareket verileri için yoklamaya başlamadan önce hala startDeviceMotionUpdatesUsingReferenceFrame: numaralı telefonu aramanız gerektiğini unutmayın. örneğin - bu sahne içeriği animasyon gereken bildiği sadece

Ayrıca SceneKit normal olarak işlemek döngü çalışır sahnede bir şeye bir animasyon eklediyseniz veya bir işlemde animatable bir özellik belirlediyseniz veya eylemleri veya fizikleri kullanarak. (Bu şekilde, bir sonraki kare sonuncu ile aynı olacaksa, cihazınızın pilini aynı şeyi tekrar tekrar çizmeyecektir.) Ancak animasyon döngüsü sırasında değişiklik yapmayı beklediğinizde, Sürekli çalıştığından emin olmalısın.

özelliğine ayarlandığında, true görünümüne ayarlamak gerçekten doğru bir yoldur - SceneKit'e animasyonlar durduğunda durmaya devam etmesini istemediğinizi bildirir. (Eğer let Apple know onlar muhtemelen bunu düzeltmek edeceğiz Evet, eğer dokümantasyon muhtemelen ... o noktada daha net olabilir.)


Son olarak, Swift ipucu: struct türleri ile özelliklerindeki üyelerine doğrudan atayabilirsiniz yepyeni bir değer oluşturmak gerek, bu yüzden yerine bu yapmadan:

cameraRollNode.eulerAngles = SCNVector3Make(0.0, 0.0, -roll) 
cameraPitchNode.eulerAngles = SCNVector3Make(pitch, 0.0, 0.0) 
cameraYawNode.eulerAngles = SCNVector3Make(0.0, yaw, 0.0) 

Bunu yapabilirsin:

cameraRollNode.eulerAngles.z = -roll 
cameraPitchNode.eulerAngles.x = pitch 
cameraYawNode.eulerAngles.y = yaw 
+0

Bu harika bir cevap - kesinlikle daha fazla oy hak ediyor! Teşekkür ederim. – StephenT

+0

Katılıyorum. Mükemmel cevap. Teşekkür ederim. – rmvz3