This site has been permanently archived. The content on this site was last updated in 2019.
Implementing "magic window" in Unity
Stay organized with collections
Save and categorize content based on your preferences.
"Magic window" allows users to view 360º content without a VR headset.
It refers to a technique whereby your app renders a single
(often full screen) monoscopic view of your 3D scene that is updated based on
the device's orientation sensor. In this way the device's screen acts as a
(seemingly magic) "window" that allows the user to look into your 3D scene.
Prerequisites
Magic window uses the device's built-in orientation sensor to match the
virtual camera's rotation to that of the device.
It does not require additional hardware features such as low persistence or
asynchronous reprojection.
Using "magic window" in hybrid apps
If you are using magic window in a hybrid app
that supports both 2D (non-VR) and VR modes:
Make sure None is added as one of the Player Settings > XR
Settings > Virtual Reality SDKs.
Unity tries to load the listed VR SDKs in order. To ensure your app starts
in 2D mode when launched from the 2D launcher, make sure None is
listed first.
At runtime, make sure to
switch to 2D mode, so that Unity no
longer updates the camera transform's position and rotation.
Depending on your app's user experience requirements, consider locking
screen rotation to Portrait or Landscape Left when magic window
mode is active.
The 2D device orientation can be locked using
Player Settings > Resolution and Presentation > Default Orientation.
Note that in older version of Unity you might need to temporarily uncheck
Player Settings > XR Settings > Virtual Reality Supported in order to
access the orientation settings.
Alternatively, see
issue 838
for an example of how to set Screen.orientation
and the
Screen.autorotate*
properties at runtime through script.
Implementing magic window
Attach the following controller script to the main camera game object
or an appropriate ancestor, such as a "player" game object.
using UnityEngine;
using UnityEngine.XR;
// Attach this controller to the main camera, or an appropriate
// ancestor thereof, such as the "player" game object.
public class GyroController : MonoBehaviour {
// Optional, allows user to drag left/right to rotate the world.
private const float DRAG_RATE = .2f;
float dragYawDegrees;
void Start () {
// Make sure orientation sensor is enabled.
Input.gyro.enabled = true;
}
void Update () {
if (XRSettings.enabled) {
// Unity takes care of updating camera transform in VR.
return;
}
// android-developers.blogspot.com/2010/09/one-screen-turn-deserves-another.html
// developer.android.com/guide/topics/sensors/sensors_overview.html#sensors-coords
//
// y x
// | Gyro upright phone | Gyro landscape left phone
// | |
// |______ x y ______|
// / \
// / \
// z z
//
//
// y
// | z Unity
// | /
// |/_____ x
//
// Update `dragYawDegrees` based on user touch.
CheckDrag ();
transform.localRotation =
// Allow user to drag left/right to adjust direction they're facing.
Quaternion.Euler (0f, -dragYawDegrees, 0f) *
// Neutral position is phone held upright, not flat on a table.
Quaternion.Euler (90f, 0f, 0f) *
// Sensor reading, assuming default `Input.compensateSensors == true`.
Input.gyro.attitude *
// So image is not upside down.
Quaternion.Euler (0f, 0f, 180f);
}
void CheckDrag () {
if (Input.touchCount != 1) {
return;
}
Touch touch = Input.GetTouch (0);
if (touch.phase != TouchPhase.Moved) {
return;
}
dragYawDegrees += touch.deltaPosition.x * DRAG_RATE;
}
}
All rights reserved. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2024-10-09 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2024-10-09 UTC."],[[["\u003cp\u003e"Magic window" lets users experience 360° content on their devices without needing a VR headset by using the device's orientation sensors.\u003c/p\u003e\n"],["\u003cp\u003eThis technique renders a monoscopic 3D scene view that updates based on device orientation, effectively turning the screen into a window into a virtual environment.\u003c/p\u003e\n"],["\u003cp\u003eIt works without specialized hardware like low persistence or asynchronous reprojection, functioning through a script attached to the main camera or a parent object like a "player".\u003c/p\u003e\n"],["\u003cp\u003eHybrid apps using "magic window" need specific settings like adding "None" to VR SDKs to ensure 2D launching and potentially locking screen orientation for optimal experience.\u003c/p\u003e\n"]]],["\"Magic window\" allows 360º content viewing without a VR headset by using a device's orientation sensor to update a monoscopic 3D scene view. In hybrid apps, set \"None\" as the first VR SDK in Player Settings, then switch to 2D mode at runtime to stop camera updates. Lock screen orientation if desired. Implementation involves attaching a controller script, such as the `GyroController`, to the main camera, which reads the orientation sensor to update camera rotation and incorporates user drag input for additional control.\n"],null,["\"Magic window\" allows users to view 360º content without a VR headset.\nIt refers to a technique whereby your app renders a single\n(often full screen) monoscopic view of your 3D scene that is updated based on\nthe device's orientation sensor. In this way the device's screen acts as a\n(seemingly magic) \"window\" that allows the user to look into your 3D scene.\n\nPrerequisites\n\nMagic window uses the device's built-in orientation sensor to match the\nvirtual camera's rotation to that of the device.\n\nIt does not require additional hardware features such as *low persistence* or\n*asynchronous reprojection*.\n\nUsing \"magic window\" in hybrid apps\n\nIf you are using magic window in a [hybrid app](/vr/develop/unity/guides/hybrid-apps)\nthat supports both 2D (non-VR) and VR modes:\n\n1. Make sure **None** is added as one of the **Player Settings \\\u003e XR\n Settings \\\u003e Virtual Reality SDKs**.\n\n Unity tries to load the listed VR SDKs in order. To ensure your app starts\n in 2D mode when launched from the 2D launcher, make sure **None** is\n listed first.\n2. At runtime, make sure to\n [switch to 2D mode](/vr/guides/unity/hybrid-apps), so that Unity no\n longer updates the camera transform's position and rotation.\n\n3. Depending on your app's user experience requirements, consider locking\n screen rotation to **Portrait** or **Landscape Left** when magic window\n mode is active.\n\n The 2D device orientation can be locked using\n **Player Settings \\\u003e Resolution and Presentation \\\u003e Default Orientation** .\n Note that in older version of Unity you might need to temporarily uncheck\n **Player Settings \\\u003e XR Settings \\\u003e Virtual Reality Supported** in order to\n access the orientation settings.\n\n Alternatively, see\n [issue 838](//github.com/googlevr/gvr-unity-sdk/issues/838#issuecomment-358404072)\n for an example of how to set `Screen.orientation` and the\n `Screen.autorotate*` properties at runtime through script.\n\nImplementing magic window\n\nAttach the following controller script to the main camera game object\nor an appropriate ancestor, such as a \"player\" game object. \n\n using UnityEngine;\n using UnityEngine.XR;\n\n // Attach this controller to the main camera, or an appropriate\n // ancestor thereof, such as the \"player\" game object.\n public class GyroController : MonoBehaviour {\n // Optional, allows user to drag left/right to rotate the world.\n private const float DRAG_RATE = .2f;\n float dragYawDegrees;\n\n void Start () {\n // Make sure orientation sensor is enabled.\n Input.gyro.enabled = true;\n }\n\n void Update () {\n if (XRSettings.enabled) {\n // Unity takes care of updating camera transform in VR.\n return;\n }\n\n // android-developers.blogspot.com/2010/09/one-screen-turn-deserves-another.html\n // developer.android.com/guide/topics/sensors/sensors_overview.html#sensors-coords\n //\n // y x\n // | Gyro upright phone | Gyro landscape left phone\n // | |\n // |______ x y ______|\n // / \\\n // / \\\n // z z\n //\n //\n // y\n // | z Unity\n // | /\n // |/_____ x\n //\n\n // Update `dragYawDegrees` based on user touch.\n CheckDrag ();\n\n transform.localRotation =\n // Allow user to drag left/right to adjust direction they're facing.\n Quaternion.Euler (0f, -dragYawDegrees, 0f) *\n\n // Neutral position is phone held upright, not flat on a table.\n Quaternion.Euler (90f, 0f, 0f) *\n\n // Sensor reading, assuming default `Input.compensateSensors == true`.\n Input.gyro.attitude *\n\n // So image is not upside down.\n Quaternion.Euler (0f, 0f, 180f);\n }\n\n void CheckDrag () {\n if (Input.touchCount != 1) {\n return;\n }\n\n Touch touch = Input.GetTouch (0);\n if (touch.phase != TouchPhase.Moved) {\n return;\n }\n\n dragYawDegrees += touch.deltaPosition.x * DRAG_RATE;\n }\n }"]]