2015-03-26 8 views
5

पर सामान्य मैं सीनकेकिट के साथ परीक्षण कर रहा था, इसलिए मैंने वर्चुअल रियलिटी टेस्ट ऐप बनाने का फैसला किया। मुझे डिवाइस गति से डेटा मिल जाएगा और फिर डेटा के आधार पर कैमरा कोण बदल जाएगा। मैं एक आईफोन 6 पर परीक्षण कर रहा था, इसलिए, कोई समस्या नहीं। जब मैं इसे आईफोन 5 और एक दोस्त के आईफोन 5 एस पर चलाता हूं तो यह चीज़ अजीब हो जाती है, तो कैमरे को घूमने में कुछ देरी होगी, आईफोन 6 पर बहुत अलग है, जो तुरंत है। एक्सकोड पर एफपीएस दोनों उपकरणों पर लगभग 60 एफपीएस रखता है, मैंने कुछ समय परीक्षण जोड़े और गति डेटा 60 हर्ट्ज के साथ-साथ दोनों उपकरणों पर भी आ रहा है। मैं हार गया हूं। https://github.com/stevenjs/VR-iOS-Experimentआईफोन 5 पर सीनिटकिट और कोरमोशन "लैगिंग" लेकिन आईफोन 6

संभव हो तो, मैं इसे कैसे ठीक करने के लिए, न केवल कोड को कॉपी & चिपकाया होने के लिए तैयार बारे में कुछ सुझाव चाहते हैं:

कोड के लिए आधार इस परियोजना है। मैं सीखना चाहता हूँ।

मैं इसे अच्छी तरह से व्याख्या नहीं कर सकते शब्दों के साथ, तो मैं आप को दिखाने के लिए क्या हो रहा है कुछ वीडियो दर्ज की गई है:

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

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

यहाँ है कोड:

// 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

अच्छा सवाल ... मुझे पता नहीं। अनुमान लगाने के लिए, मैं कहूंगा कि इसमें गति अद्यतन कतार और एससीएन प्रतिपादन पाश के बीच सिंक के साथ कुछ करना है। उन दो 60 हर्ट्ज प्रक्रियाओं को स्वतंत्र रूप से होने और उनके बीच संवाद करने की कोशिश करने के बजाय, आप चीजों को एक ही 60 हर्ट्ज लूप में जोड़ना चाहते हैं - यानी, आपके दृश्य में प्रतिनिधि डेटा के लिए मतदान 'अद्यतन' विधि प्रस्तुत करना। (देखें ['CMMotionManager' दस्तावेज़] में अवलोकन] (https://developer.apple.com/library/ios/documentation/CoreMotion/Reference/CMMotionManager_Class/index.html)। – rickster

+0

@rickster धन्यवाद! जैसा कि आपने कहा था, मैं इसे लागू करने की कोशिश कर रहा हूं, अभी मेरा व्यू कंट्रोलर प्रतिनिधि है, लेकिन प्रतिनिधि विधि 'रेंडर (रेंडरर: एससीएनएससीएनएंडरर, अपडेटएटटाइम: एनएसटीइम इंटरवल)' को केवल तीन बार कहा जाता है। शायद रेंडर विधि फ्रेम को अद्यतन करने वाली एकमात्र चीज़ है? यह शॉर्ट सर्किट की तरह ही है? –

+0

युप, जब मैंने विधि के अंत में 'sceneView.playing = true' जोड़ा, तो इसने दृश्य किट को हमेशा के लिए प्रतिपादन रखने के लिए मजबूर किया, जो काम करता था। मुझे आश्चर्य है कि ऐसा करने का सही तरीका क्या है? –

उत्तर

11

वैसे यह सिर्फ एक झटका था, लेकिन मुझे लगता है कि यह सही हो गया है तो चलो इसे औपचारिक बनाएं!

आपकी समस्या यह प्रतीत होती है कि मुख्य थ्रेड पर कोर के लिए दो 60 हर्ट्ज टाइमर/लूप हैं - कोरमोशन अपडेट कतार, और सीनकेट रेंडरिंग लूप। आप प्रभावी रूप से एक से दूसरे में संचार कर रहे हैं, जिसमें आप CoreMotion अद्यतन हैंडलर में सीनकिट स्थिति सेट कर रहे हैं, और उम्मीद करते हैं कि दृश्यकिट रेंडर लूप इसे उसी फ्रेम पर उठाता है।

(मुझे संदेह है कि हार्डवेयर अंतर यह है कि आईफोन 6 में पर्याप्त प्रदर्शन ओवरहेड है कि समय ठीक से काम करने के लिए होता है, और पुराना हार्डवेयर नहीं करता है - इसलिए सीनकिट मॉडल पदों को उठा रहा है जो एक फ्रेम या दो पीछे हैं आपका गति डेटा।)

इसके बजाय, उसी 60Hz लूप में सब कुछ करें। (वास्तव में, यह एक सामान्य सामान्य सलाह है, चाहे आपका अन्य 60 हर्ट्ज इवेंट स्रोत कोरमोशन या कुछ और है - एक गेम इंजन या इसी तरह के रीयल-टाइम रेंडरर में, आपको अपने द्वारा किए गए सभी कार्यों को निर्देशित करने के लिए लक्ष्य फ़्रेमेट करना चाहिए।)

इसका मतलब है कि आपको मतदान डेटा के लिए मतदान करना चाहिए, इसे आपको धक्का नहीं दे रहा है - आप केवल फ्रेम स्थिति के टाइमस्टैम्प के रूप में गति स्थिति की देखभाल करते हैं, न कि 1/60 सेकेंड से पहले नमूना, या यदि आपने फ्रेम गिरा दिया तो पिछले कई नमूने। scene renderer delegate के साथ सीनकिट रेंडरिंग लूप में हुक करें, अपने renderer:updateAtTime: विधि में CoreMotion's deviceMotion पढ़ें और वहां अपने मॉडल रोटेशन सेट करें। ध्यान दें कि गति डेटा के लिए मतदान शुरू करने से पहले आपको अभी भी startDeviceMotionUpdatesUsingReferenceFrame: पर कॉल करने की आवश्यकता है।

इसके अलावा, सीनिटकिट आमतौर पर केवल रेंडर लूप चलाता है जब यह जानता है कि दृश्य सामग्री को एनिमेट करने की आवश्यकता है - उदा। यदि आपने दृश्य में किसी चीज़ को एनीमेशन संलग्न किया है, या लेनदेन में एक एनिमेटेबल संपत्ति सेट की है, या क्रिया या भौतिकी का उपयोग कर रहा है। (इस तरह, यदि अगली फ्रेम प्रस्तुत की गई अंतिम की तरह ही होगी, तो यह आपके डिवाइस की बैटरी को बार-बार एक ही चीज़ को चित्रित नहीं करेगा।) लेकिन जब आप एनीमेशन लूप के दौरान परिवर्तन करने की उम्मीद कर रहे हैं, आपको यह सुनिश्चित करना होगा कि यह हर समय चल रहा है।

पर आपके विचार पर playing संपत्ति को सेट करना वास्तव में ऐसा करने का सही तरीका है - यह सीनकेकिट को बताता है कि आप इसे प्रतिपादन रखना चाहते हैं, एनिमेशन बंद होने पर रोकें। (हाँ, प्रलेखन शायद स्पष्ट है कि बिंदु पर हो सकता है ... अगर आप let Apple know वे शायद इसे ठीक कर देंगे।)


अंत में, एक स्विफ्ट टिप: आप सीधे सदस्यों को struct प्रकार के साथ गुण में प्रदान कर सकते हैं एक पूरी नई मूल्य के निर्माण के लिए की आवश्यकता होगी, है, तो बजाय ऐसा किए बिना:

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

आप ऐसा कर सकते हैं:

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

यह एक अच्छा जवाब है - निश्चित रूप से अधिक वोटों का हकदार है! धन्यवाद। – StephenT

+0

मैं सहमत हूं। बहुत बढ़िया जवाब। धन्यवाद। – rmvz3

संबंधित मुद्दे