Windows 10, UWP, HoloLens and Switching 2D/3D Views

NB: The usual blog disclaimer for this site applies to posts around HoloLens. I am not on the HoloLens team. I have no details on HoloLens other than what is on the public web and so what I post here is just from my own experience experimenting with pieces that are publicly available and you should always check out the official developer site for the product documentation.

One of the things that I wanted to understand a bit better when I wrote this post;

Baby Steps on my HoloLens Developer Journey

was the interchange between 2D and 3D views on the HoloLens as discussed in this document;

App Model – Switching Views

and I wanted to experiment with seeing if I could get an app up and running which switched between a 2D XAML based view and a 3D Unity based view.

To get going with that, I made a fairly blank Unity project in accordance with the steps here;

Configuring a Unity project for HoloLens

and then I added a cube into my scene so that I had something to look at;

image

and then made sure that I was exporting my project as a XAML based project as I mentioned in this previous post;

Windows 10, UWP, Unity, HoloLens– Small Explorations of D3D and XAML based Unity Projects 

as I had a suspicion that the code that I was going to write might be dependent on having the initial view in the app come from the 2D/XAML world rather than the 3D/D3D world although I have yet to test that suspicion so apply a pinch of salt.

I placed a simple script onto my Cube in the scene above although the script is really a global handler so it didn’t need to be attached onto the cube but I needed something to hang my hat on and so I used the Cube;

image

and that script looks like this;

using UnityEngine;
using System.Collections;
using UnityEngine.VR.WSA.Input;

public class TestScript : MonoBehaviour
{

  GestureRecognizer recognizer;
  // Use this for initialization
  void Start()
  {
    this.recognizer = new GestureRecognizer();
    this.recognizer.TappedEvent += OnTapped;
    this.recognizer.StartCapturingGestures();
  }

  private void OnTapped(InteractionSourceKind source, int tapCount, Ray headRay)
  {
#if !UNITY_EDITOR
    ViewLibrary.ViewManagement.SwitchTo2DViewAsync();
#endif
  }

  // Update is called once per frame
  void Update()
  {

  }
}

and so it’s a very simple script and it’s just waiting for a tap (anywhere) before making a call into this SwitchTo2DViewAsync function and I’ve hidden that from the Unity editor so that it doesn’t have to think about it. The Tap isn’t specific to the Cube in any way hence my earlier comment about the script not really ‘belonging’ to the Cube.

That ViewLibrary code lives in a separate class library that I have tried to bring in to the Unity environment as a plugin;

image

and the way I did that came from this previous blog post;

Windows 10 UWP Unity and Adding a Reference to a (UWP) Class Library

The code inside that ViewManagement class looks like this and it’s a bit experimental at the time of writing but it “seems to work”;

namespace ViewLibrary
{
  using System;
  using System.Threading.Tasks;
  using Windows.ApplicationModel.Core;
  using Windows.UI;
  using Windows.UI.Core;
  using Windows.UI.ViewManagement;
  using Windows.UI.Xaml;
  using Windows.UI.Xaml.Controls;
  using Windows.UI.Xaml.Media;

  public static class ViewManagement
  {
    public static async Task SwitchTo2DViewAsync()
    {
      if (coreView3d == null)
      {
        coreView3d = CoreApplication.MainView;
      }
      if (coreView2d == null)
      {
        coreView2d = CoreApplication.CreateNewView();

        await RunOnDispatcherAsync(
          coreView2d, 
          async () =>
          {
            Window.Current.Content = Create2dUI();
          }
        );
      }
      await RunOnDispatcherAsync(coreView2d, SwitchViewsAsync);
    }
    static UIElement Create2dUI()
    {
      var button = new Button()
      {
        HorizontalAlignment = HorizontalAlignment.Stretch,
        VerticalAlignment = VerticalAlignment.Stretch,
        Content = "Back to 3D",
        Background = new SolidColorBrush(Colors.Red)
      };
      button.Click += async (s, e) =>
      {
        await SwitchTo3DViewAsync();
      };
      return (button);
    }
    static async Task RunOnDispatcherAsync(CoreApplicationView view, 
      Func<Task> action)
    {
      await view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        () => action());
    }
    public static async Task SwitchTo3DViewAsync()
    {
      await RunOnDispatcherAsync(coreView3d, SwitchViewsAsync);
    }
    static async Task SwitchViewsAsync()
    {
      var view = ApplicationView.GetForCurrentView();
      await ApplicationViewSwitcher.SwitchAsync(view.Id);
      Window.Current.Activate();
    }
    static CoreApplicationView coreView3d;
    static CoreApplicationView coreView2d;
  }
}

Mostly, that code came from this blog post about using multiple views in a regular UWP app but I manipulated it around a little here.

If I run this up on the emulator or an a device then I see my initial holographic view of the app containing my Cube;

image

and then if I tap I see;

image

and then if I Click I see;

image

I wouldn’t say that I have a 100% grip on this at the time of finishing this post but I think I understand it better than when I started writing it Smile

I’d like to dig into whether this same approach works with a project that has been exported as D3D rather than as XAML and I’ll update the post as/when I figure that out.

2 thoughts on “Windows 10, UWP, HoloLens and Switching 2D/3D Views

  1. nice work. going from 3D -> 2D seems to be infinitely easier than doing the reverse. What If i have a UWP app that I want on Hololens but want to make it awesomer by adding some 3D content/capabilities to it? This has been something I’ve had trouble figuring out.

    • I’m figuring things out too but I guess one aspect of that is whether you have a separate package for HoloLens that includes the 3D content as you wouldn’t want to ship that package to other devices where that content doesn’t get used. Beyond that you can use this technique to switch 2D->3D and show that content. The code I had here did go 3D->2D but it did start with 2D so I haven’t yet tried what happens here if you start in 3D.

Comments are closed.