{"id":15249,"date":"2014-11-07T12:27:53","date_gmt":"2014-11-07T17:27:53","guid":{"rendered":"http:\/\/blog.xamarin.com\/?p=15249"},"modified":"2019-04-02T15:53:20","modified_gmt":"2019-04-02T22:53:20","slug":"programming-for-google-cardboard-on-ios-using-f","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/programming-for-google-cardboard-on-ios-using-f\/","title":{"rendered":"Programming for Google Cardboard on iOS using F#"},"content":{"rendered":"<p>One of the highlights of <a href=\"https:\/\/evolve.xamarin.com\/\">Xamarin Evolve<\/a> is the Darwin Lounge, a hall filled with programmable devices ranging from robots to iBeacons and quadcopters to wearables. One thing that was particularly intriguing this year was a stack of kits from <a href=\"http:\/\/www.dodocase.com\/products\/google-cardboard-vr-goggle-toolkit\">DodoCase<\/a>, \u201cinspired by Google Cardboard.\u201d Google Cardboard is an inexpensive stereoscope that exploits the ridiculously small pixels of modern phones. Instead of synchronizing two displays, it directs your eyes\u00a0separately to the two halves of a phone screen in portrait mode.<\/p>\n<p><a href=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/cardboard.jpg\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-15253\" src=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/cardboard-300x237.jpg\" alt=\"cardboard\" width=\"300\" height=\"237\" \/><\/a><\/p>\n<p>Unfortunately, all of the resources for programming Google Cardboard have been Android only. This is not the Xamarin way and could not stand! Luckily, <a href=\"https:\/\/twitter.com\/joelmartinez\">Joel Martinez<\/a> had written a 3D demo for our talk,\u00a0<a href=\"https:\/\/www.youtube.com\/watch?v=2-v4jdQJ5Wo\">Make Your Apps Awesome With F#<\/a>, and it was just a\u00a0matter of a quick hacking session to see our <a href=\"http:\/\/www.xamarin.com\/ios\/\">Xamarin.iOS<\/a> code in glorious stereoscopic 3D.<\/p>\n<p><a href=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/before_and_after.png\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-15252\" src=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/before_and_after-300x225.png\" alt=\"before_and_after\" width=\"300\" height=\"225\" \/><\/a><\/p>\n<h2 id=\"functionalrefactoring\">Functional Refactoring<\/h2>\n<p>As Mike Bluestein has written previously, the <a href=\"\/3d-in-ios-8-with-scene-kit\/\">easiest way to program 3D on iOS is to use Scene Kit<\/a>,\u00a0which\u00a0is what Joel and I had done for our demo. Stereoscopic programming in Scene Kit, as it turns out, is easy!<\/p>\n<p>One great aspect of <a href=\"http:\/\/developer.xamarin.com\/guides\/cross-platform\/fsharp\/fsharp_support_overview\/\" target=\"_blank\" rel=\"noopener\">F#<\/a> and the functional programming style is that refactoring is often easier than object-oriented refactoring. Instead of creating new objects and data structures, you\u2019re generally focusing on \u201cminimizing the moving parts\u201d and extracting common functionality into reliable functions.<\/p>\n<p>For instance, the first thing we needed to do was switch from a single <code>UIView<\/code> to two side-by-side views. We refactored this code:<\/p>\n<pre><code>\/\/Configure view  \r\nlet r = new RectangleF(new PointF(0.0f, 0.0f), new SizeF(UIScreen.MainScreen.Bounds.Size))  \r\nlet s = new SCNView(r)  \r\nconfigView s scene |&gt; ignore  \r\nthis.View &lt;- s\r\n<\/code><\/pre>\n<p>into this code:<\/p>\n<pre><code>\/\/Configure views  \r\nlet outer = new UIView(UIScreen.MainScreen.Bounds)\r\n\r\nlet ss =  \r\n    [\r\n        new RectangleF(new PointF(0.0f, 0.0f), new SizeF(float32 UIScreen.MainScreen.Bounds.Width \/ 2.0f - 1.0f, UIScreen.MainScreen.Bounds.Height));  \r\n        new RectangleF(new PointF(float32 UIScreen.MainScreen.Bounds.Width \/ 2.0f + 1.0f, 0.0f), new SizeF(UIScreen.MainScreen.Bounds.Width \/ 2.0f -1.0f, UIScreen.MainScreen.Bounds.Height));  \r\n    ]\r\n    |&gt; List.map (fun r -&gt; new SCNView(r))  \r\n    |&gt; List.map (fun s -&gt; outer.AddSubview(configView s scene); s)\r\n\r\nthis.View &lt;- outer\r\n<\/code><\/pre>\n<p>Although you may be more familiar with C# than F#, you should be able to follow what\u2019s going on in the original snippet. We had a <code>RectangleF<\/code> as big as the entire screen\u2019s <code>Bounds<\/code>. We created a single <code>SCNView<\/code> called <code>s<\/code>. We configured <code>s<\/code> to show our <code>scene<\/code> and then, because we don\u2019t need to do any more manipulation on the result of that calculation, we called the <code>ignore<\/code> function with the result (the <code>|&gt;<\/code> is F#\u2019s pipe operator, which works just like the familiar pipe operator on the UNIX command-line or PowerShell). Finally, we assigned this single <code>SCNView<\/code> to be the main <code>View<\/code> of our controller object.<\/p>\n<p>To refactor, we introduce an <code>outer<\/code> view that will contain our two eye-specific views. We then use the <code>|&gt;<\/code> operator again to:<\/p>\n<ul>\n<li>Create a 2-element list of <code>RectangleF<\/code>s, each a half-screen wide<\/li>\n<li>Create an <code>SCNView<\/code> for each one of those<\/li>\n<li>Configure each <code>SCNView<\/code> with the <code>scene<\/code><\/li>\n<li>Add them to the <code>outer<\/code> container <code>UIView<\/code><\/li>\n<\/ul>\n<p>Now we have two side-by-side <code>SCNView<\/code>s, but each is rendering the exact same scene, so there is no 3D effect. Scene Kit is a scene-graph toolkit, and to get a stereoscopic 3D effect, we\u2019re going to need two camera nodes slightly separated in space. That\u2019s easy. We replace:<\/p>\n<pre><code>\/\/Camera!  \r\nlet camNode = new SCNNode()  \r\ncamNode.Position &lt;- new SCNVector3(0.0F, 0.0F, 9.0F)  \r\nscene.RootNode.AddChildNode camNode\r\n<\/code><\/pre>\n<p>With:<\/p>\n<pre><code>\/\/Cameras!  \r\nlet camNode = new SCNNode()  \r\nlet leftCamera = buildCamera camNode (new SCNVector3 (0.0F, 0.0F, 9.0F))  \r\nlet rightCamera = buildCamera camNode (new SCNVector3 (0.2F, 0.0F, 9.0F))\r\n<\/code><\/pre>\n<p>Note the slight difference in the first argument to the <code>SCNVector3<\/code> constructor \u2013 this eye-position vector is the \u201cmoving part\u201d that we want to isolate. So now our <code>camNode<\/code> has two subnodes, each containing a node that defines one of our eye positions.<\/p>\n<p>The <code>buildCamera<\/code> function is:<\/p>\n<pre><code>let buildCamera (parent : SCNNode) loc =  \r\n    let c = new SCNNode()  \r\n    c.Camera &lt;- new SCNCamera()  \r\n    parent.AddChildNode (c)  \r\n    c.Position &lt;- loc  \r\n    c\r\n<\/code><\/pre>\n<p>It\u2019s worth emphasizing that this function is strongly-typed. Even though it doesn\u2019t <em>explicitly<\/em> state that <code>loc<\/code> is an <code>SCNVector<\/code> or that it returns an <code>SCNNode<\/code>, F#\u2019s type inference is powerful enough to figure that out and enforce the types at compile-time. (As for programming style: \u201cIs it better to explicitly declare types in the function signature or let them be implicit?\u201d is the type of discussion that happens both in the Darwin Lounge and at Xamarin Evolve parties\u2026)<\/p>\n<p>Now we have two scenes and two camera nodes. To join them together, we use:<\/p>\n<pre><code>\/\/Set PoVs to shifted cameras  \r\nss.Head.PointOfView &lt;- leftCameraNode  \r\nss.Tail.Head.PointOfView &lt;- rightCameraNode\r\n<\/code><\/pre>\n<p>And there you have it! In the following image, you can see the converging perspective of the building climbing into the sky.<\/p>\n<p><a href=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/living_in_stereo.jpg\"><img decoding=\"async\" class=\"alignnone size-medium wp-image-15254\" src=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/living_in_stereo-300x169.jpg\" alt=\"living_in_stereo\" width=\"300\" height=\"169\" \/><\/a><\/p>\n<p>This might not be ready for the <em>Avatar<\/em> sequel, but it\u2019s really cool when viewed through Cardboard!<\/p>\n<p>Here\u2019s something James Cameron can\u2019t do, though: exploit the gyroscope and accelerometer on iOS devices. This block of code shifts the orientation of the <code>camNode<\/code> camera node so that it tracks the direction in which the user is looking:<\/p>\n<pre><code>    let rr = CMAttitudeReferenceFrame.XArbitraryCorrectedZVertical  \r\n    this.motion.DeviceMotionUpdateInterval &lt;- float (1.0f \/ 30.0f)  \r\n    this.motion.StartDeviceMotionUpdates (rr,NSOperationQueue.CurrentQueue, (fun d e -&gt;  \r\n        let a = this.motion.DeviceMotion.Attitude  \r\n        let q = a.Quaternion  \r\n        let dq = new SCNQuaternion(float32 q.x, float32 q.y, float32 q.z, float32 q.w)  \r\n        let dqm = SCNQuaternion.Multiply (dq, SCNQuaternion.FromAxisAngle(SCNVector3.UnitZ, piover2))  \r\n        camNode.Orientation &lt;- dqm\r\n\r\n       ()  \r\n    ))\r\n<\/code><\/pre>\n<p>Which looks like this in action:<\/p>\n<p><center><iframe width=\"640\" height=\"390\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\" src=\"\/\/www.youtube.com\/embed\/ERlka1WXSwg\"><\/iframe><\/center>\nTo experiment with stereoscopic 3D in Xamarin and F#, <a href=\"http:\/\/developer.xamarin.com\/samples\/monotouch\/ios8\/SceneKitFSharp\/\">download this Starter-compatible project<\/a> in Xamarin Studio on Mac or Windows.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the highlights of Xamarin Evolve is the Darwin Lounge, a hall filled with programmable devices ranging from robots to iBeacons and quadcopters to wearables. One thing that was particularly intriguing this year was a stack of kits from DodoCase, \u201cinspired by Google Cardboard.\u201d Google Cardboard is an inexpensive stereoscope that exploits the ridiculously [&hellip;]<\/p>\n","protected":false},"author":556,"featured_media":39167,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[6,4],"class_list":["post-15249","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-ios","tag-xamarin-platform"],"acf":[],"blog_post_summary":"<p>One of the highlights of Xamarin Evolve is the Darwin Lounge, a hall filled with programmable devices ranging from robots to iBeacons and quadcopters to wearables. One thing that was particularly intriguing this year was a stack of kits from DodoCase, \u201cinspired by Google Cardboard.\u201d Google Cardboard is an inexpensive stereoscope that exploits the ridiculously [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/15249","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/556"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=15249"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/15249\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/39167"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=15249"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=15249"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=15249"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}