Mercurial > hg > Game > Games
diff Orchestland/Assets/OVR/Scripts/OVRDisplay.cs @ 1:f7675884f2a1
Add Orchestland project
author | Daiki OYAKAWA <e135764@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2015 23:09:20 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orchestland/Assets/OVR/Scripts/OVRDisplay.cs Fri Jul 17 23:09:20 2015 +0900 @@ -0,0 +1,644 @@ +/************************************************************************************ + +Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +using System; +using System.Runtime.InteropServices; +using UnityEngine; +using Ovr; + +/// <summary> +/// Manages an Oculus Rift head-mounted display (HMD). +/// </summary> +public class OVRDisplay +{ + /// <summary> + /// Specifies the size and field-of-view for one eye texture. + /// </summary> + public struct EyeRenderDesc + { + /// <summary> + /// The horizontal and vertical size of the texture. + /// </summary> + public Vector2 resolution; + + /// <summary> + /// The angle of the horizontal and vertical field of view in degrees. + /// </summary> + public Vector2 fov; + } + + /// <summary> + /// Contains latency measurements for a single frame of rendering. + /// </summary> + public struct LatencyData + { + /// <summary> + /// The time it took to render both eyes in seconds. + /// </summary> + public float render; + + /// <summary> + /// The time it took to perform TimeWarp in seconds. + /// </summary> + public float timeWarp; + + /// <summary> + /// The time between the end of TimeWarp and scan-out in seconds. + /// </summary> + public float postPresent; + } + + /// <summary> + /// If true, a physical HMD is attached to the system. + /// </summary> + /// <value><c>true</c> if is present; otherwise, <c>false</c>.</value> + public bool isPresent + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return (OVRManager.capiHmd.GetTrackingState().StatusFlags & (uint)StatusBits.HmdConnected) != 0; +#else + return OVR_IsHMDPresent(); +#endif + } + } + + private int prevScreenWidth; + private int prevScreenHeight; + private bool needsSetTexture; + private float prevVirtualTextureScale; + private bool prevFullScreen; + private OVRPose[] eyePoses = new OVRPose[(int)OVREye.Count]; + private EyeRenderDesc[] eyeDescs = new EyeRenderDesc[(int)OVREye.Count]; + private RenderTexture[] eyeTextures = new RenderTexture[eyeTextureCount]; + private int[] eyeTextureIds = new int[eyeTextureCount]; + private int currEyeTextureIdx = 0; + private static int frameCount = 0; + +#if !UNITY_ANDROID && !UNITY_EDITOR + private bool needsSetViewport; +#endif + +#if UNITY_ANDROID && !UNITY_EDITOR + private const int eyeTextureCount = 3 * (int)OVREye.Count; // triple buffer +#else + private const int eyeTextureCount = 1 * (int)OVREye.Count; +#endif + +#if UNITY_ANDROID && !UNITY_EDITOR + private int nextEyeTextureIdx = 0; +#endif + + /// <summary> + /// Creates an instance of OVRDisplay. Called by OVRManager. + /// </summary> + public OVRDisplay() + { +#if !UNITY_ANDROID || UNITY_EDITOR + needsSetTexture = true; + prevFullScreen = Screen.fullScreen; + prevVirtualTextureScale = OVRManager.instance.virtualTextureScale; +#elif !UNITY_ANDROID && !UNITY_EDITOR + needsSetViewport = true; +#endif + + ConfigureEyeDesc(OVREye.Left); + ConfigureEyeDesc(OVREye.Right); + + for (int i = 0; i < eyeTextureCount; i += 2) + { + ConfigureEyeTexture(i, OVREye.Left, OVRManager.instance.nativeTextureScale); + ConfigureEyeTexture(i, OVREye.Right, OVRManager.instance.nativeTextureScale); + } + } + + /// <summary> + /// Updates the internal state of the OVRDisplay. Called by OVRManager. + /// </summary> + public void Update() + { + // HACK - needed to force DX11 into low persistence mode, remove after Unity patch release + if (frameCount < 2) + { + uint caps = OVRManager.capiHmd.GetEnabledCaps(); + caps ^= (uint)HmdCaps.LowPersistence; + OVRManager.capiHmd.SetEnabledCaps(caps); + } + + UpdateViewport(); + UpdateTextures(); + } + + /// <summary> + /// Marks the beginning of all rendering. + /// </summary> + public void BeginFrame() + { + bool updateFrameCount = !(OVRManager.instance.timeWarp && OVRManager.instance.freezeTimeWarp); + if (updateFrameCount) + { + frameCount++; + } + + OVRPluginEvent.IssueWithData(RenderEventType.BeginFrame, frameCount); + } + + /// <summary> + /// Marks the end of all rendering. + /// </summary> + public void EndFrame() + { + OVRPluginEvent.Issue(RenderEventType.EndFrame); + } + + /// <summary> + /// Gets the head pose at the current time or predicted at the given time. + /// </summary> + public OVRPose GetHeadPose(double predictionTime = 0d) + { +#if !UNITY_ANDROID || UNITY_EDITOR + double abs_time_plus_pred = Hmd.GetTimeInSeconds() + predictionTime; + + TrackingState state = OVRManager.capiHmd.GetTrackingState(abs_time_plus_pred); + + return state.HeadPose.ThePose.ToPose(); +#else + float px = 0, py = 0, pz = 0, ow = 0, ox = 0, oy = 0, oz = 0; + + double atTime = Time.time + predictionTime; + OVR_GetCameraPositionOrientation(ref px, ref py, ref pz, + ref ox, ref oy, ref oz, ref ow, atTime); + + return new OVRPose + { + position = new Vector3(px, py, -pz), + orientation = new Quaternion(-ox, -oy, oz, ow), + }; +#endif + } + +#if UNITY_ANDROID && !UNITY_EDITOR + private float w = 0, x = 0, y = 0, z = 0, fov = 90f; +#endif + + /// <summary> + /// Gets the pose of the given eye, predicted for the time when the current frame will scan out. + /// </summary> + public OVRPose GetEyePose(OVREye eye) + { +#if !UNITY_ANDROID || UNITY_EDITOR + bool updateEyePose = !(OVRManager.instance.timeWarp && OVRManager.instance.freezeTimeWarp); + if (updateEyePose) + { + eyePoses[(int)eye] = OVR_GetRenderPose(frameCount, (int)eye).ToPose(); + } + + return eyePoses[(int)eye]; +#else + if (eye == OVREye.Left) + OVR_GetSensorState( + false, + ref w, + ref x, + ref y, + ref z, + ref fov, + ref OVRManager.timeWarpViewNumber); + + Quaternion rot = new Quaternion(-x, -y, z, w); + + float eyeOffsetX = 0.5f * OVRManager.profile.ipd; + eyeOffsetX = (eye == OVREye.Left) ? -eyeOffsetX : eyeOffsetX; + Vector3 pos = rot * new Vector3(eyeOffsetX, 0.0f, 0.0f); + + return new OVRPose + { + position = pos, + orientation = rot, + }; +#endif + } + + /// <summary> + /// Gets the given eye's projection matrix. + /// </summary> + /// <param name="eyeId">Specifies the eye.</param> + /// <param name="nearClip">The distance to the near clipping plane.</param> + /// <param name="farClip">The distance to the far clipping plane.</param> + public Matrix4x4 GetProjection(int eyeId, float nearClip, float farClip) + { +#if !UNITY_ANDROID || UNITY_EDITOR + FovPort fov = OVRManager.capiHmd.GetDesc().DefaultEyeFov[eyeId]; + + return Hmd.GetProjection(fov, nearClip, farClip, true).ToMatrix4x4(); +#else + return new Matrix4x4(); +#endif + } + + /// <summary> + /// Occurs when the head pose is reset. + /// </summary> + public event System.Action RecenteredPose; + + /// <summary> + /// Recenters the head pose. + /// </summary> + public void RecenterPose() + { +#if !UNITY_ANDROID || UNITY_EDITOR + OVRManager.capiHmd.RecenterPose(); +#else + OVR_ResetSensorOrientation(); +#endif + + if (RecenteredPose != null) + { + RecenteredPose(); + } + } + + /// <summary> + /// Gets the current acceleration of the head. + /// </summary> + public Vector3 acceleration + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return OVRManager.capiHmd.GetTrackingState().HeadPose.LinearAcceleration.ToVector3(); +#else + float x = 0.0f, y = 0.0f, z = 0.0f; + OVR_GetAcceleration(ref x, ref y, ref z); + return new Vector3(x, y, z); +#endif + } + } + + /// <summary> + /// Gets the current angular velocity of the head. + /// </summary> + public Vector3 angularVelocity + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return OVRManager.capiHmd.GetTrackingState().HeadPose.AngularVelocity.ToVector3(); +#else + float x = 0.0f, y = 0.0f, z = 0.0f; + OVR_GetAngularVelocity(ref x, ref y, ref z); + return new Vector3(x, y, z); +#endif + } + } + + /// <summary> + /// Gets the resolution and field of view for the given eye. + /// </summary> + public EyeRenderDesc GetEyeRenderDesc(OVREye eye) + { + return eyeDescs[(int)eye]; + } + + /// <summary> + /// Gets the currently active render texture for the given eye. + /// </summary> + public RenderTexture GetEyeTexture(OVREye eye) + { + return eyeTextures[currEyeTextureIdx + (int)eye]; + } + + /// <summary> + /// Gets the currently active render texture's native ID for the given eye. + /// </summary> + public int GetEyeTextureId(OVREye eye) + { + return eyeTextureIds[currEyeTextureIdx + (int)eye]; + } + + /// <summary> + /// True if the direct mode display driver is active. + /// </summary> + public bool isDirectMode + { + get + { +#if !UNITY_ANDROID || UNITY_EDITOR + uint caps = OVRManager.capiHmd.GetDesc().HmdCaps; + uint mask = caps & (uint)HmdCaps.ExtendDesktop; + return mask == 0; +#else + return false; +#endif + } + } + + /// <summary> + /// If true, direct mode rendering will also show output in the main window. + /// </summary> + public bool mirrorMode + { + get + { +#if !UNITY_ANDROID || UNITY_EDITOR + uint caps = OVRManager.capiHmd.GetEnabledCaps(); + return (caps & (uint)HmdCaps.NoMirrorToWindow) == 0; +#else + return false; +#endif + } + + set + { +#if !UNITY_ANDROID || UNITY_EDITOR + uint caps = OVRManager.capiHmd.GetEnabledCaps(); + + if (((caps & (uint)HmdCaps.NoMirrorToWindow) == 0) == value) + return; + + if (value) + caps &= ~(uint)HmdCaps.NoMirrorToWindow; + else + caps |= (uint)HmdCaps.NoMirrorToWindow; + + OVRManager.capiHmd.SetEnabledCaps(caps); +#endif + } + } + + /// <summary> + /// If true, TimeWarp will be used to correct the output of each OVRCameraRig for rotational latency. + /// </summary> + internal bool timeWarp + { + get { return (distortionCaps & (int)DistortionCaps.TimeWarp) != 0; } + set + { + if (value != timeWarp) + distortionCaps ^= (int)DistortionCaps.TimeWarp; + } + } + + /// <summary> + /// If true, VR output will be rendered upside-down. + /// </summary> + internal bool flipInput + { + get { return (distortionCaps & (int)DistortionCaps.FlipInput) != 0; } + set + { + if (value != flipInput) + distortionCaps ^= (int)DistortionCaps.FlipInput; + } + } + + /// <summary> + /// Enables and disables distortion rendering capabilities from the Ovr.DistortionCaps enum. + /// </summary> + public uint distortionCaps + { + get + { + return _distortionCaps; + } + + set + { + if (value == _distortionCaps) + return; + + _distortionCaps = value; +#if !UNITY_ANDROID || UNITY_EDITOR + OVR_SetDistortionCaps(value); +#endif + } + } + private uint _distortionCaps = +#if (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) + (uint)DistortionCaps.ProfileNoTimewarpSpinWaits | +#endif + (uint)DistortionCaps.Chromatic | + (uint)DistortionCaps.Vignette | + (uint)DistortionCaps.SRGB | + (uint)DistortionCaps.Overdrive; + + /// <summary> + /// Gets the current measured latency values. + /// </summary> + public LatencyData latency + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + float[] values = { 0.0f, 0.0f, 0.0f }; + float[] latencies = OVRManager.capiHmd.GetFloatArray("DK2Latency", values); + + return new LatencyData + { + render = latencies[0], + timeWarp = latencies[1], + postPresent = latencies[2] + }; +#else + return new LatencyData + { + render = 0.0f, + timeWarp = 0.0f, + postPresent = 0.0f + }; +#endif + } + } + + private void UpdateViewport() + { +#if !UNITY_ANDROID && !UNITY_EDITOR + needsSetViewport = needsSetViewport + || Screen.width != prevScreenWidth + || Screen.height != prevScreenHeight; + + if (needsSetViewport) + { + SetViewport(0, 0, Screen.width, Screen.height); + + prevScreenWidth = Screen.width; + prevScreenHeight = Screen.height; + + needsSetViewport = false; + } +#endif + } + + private void UpdateTextures() + { + for (int i = 0; i < eyeTextureCount; i++) + { + if (!eyeTextures[i].IsCreated()) + { + eyeTextures[i].Create(); + eyeTextureIds[i] = eyeTextures[i].GetNativeTextureID(); + +#if !UNITY_ANDROID || UNITY_EDITOR + needsSetTexture = true; +#endif + } + } + +#if !UNITY_ANDROID || UNITY_EDITOR + needsSetTexture = needsSetTexture + || OVRManager.instance.virtualTextureScale != prevVirtualTextureScale + || Screen.fullScreen != prevFullScreen + || OVR_UnityGetModeChange(); + + if (needsSetTexture) + { + for (int i = 0; i < eyeTextureCount; i++) + { + if (eyeTextures[i].GetNativeTexturePtr() == System.IntPtr.Zero) + return; + + OVR_SetTexture(i, eyeTextures[i].GetNativeTexturePtr(), OVRManager.instance.virtualTextureScale); + } + + prevVirtualTextureScale = OVRManager.instance.virtualTextureScale; + prevFullScreen = Screen.fullScreen; + OVR_UnitySetModeChange(false); + + needsSetTexture = false; + } +#else + currEyeTextureIdx = nextEyeTextureIdx; + nextEyeTextureIdx = (nextEyeTextureIdx + 2) % eyeTextureCount; +#endif + } + + private void ConfigureEyeDesc(OVREye eye) + { +#if !UNITY_ANDROID || UNITY_EDITOR + HmdDesc desc = OVRManager.capiHmd.GetDesc(); + FovPort fov = desc.DefaultEyeFov[(int)eye]; + fov.LeftTan = fov.RightTan = Mathf.Max(fov.LeftTan, fov.RightTan); + fov.UpTan = fov.DownTan = Mathf.Max(fov.UpTan, fov.DownTan); + + // Configure Stereo settings. Default pixel density is one texel per pixel. + float desiredPixelDensity = 1f; + Sizei texSize = OVRManager.capiHmd.GetFovTextureSize((Ovr.Eye)eye, fov, desiredPixelDensity); + + float fovH = 2f * Mathf.Rad2Deg * Mathf.Atan(fov.LeftTan); + float fovV = 2f * Mathf.Rad2Deg * Mathf.Atan(fov.UpTan); + + eyeDescs[(int)eye] = new EyeRenderDesc() + { + resolution = texSize.ToVector2(), + fov = new Vector2(fovH, fovV) + }; +#else + eyeDescs[(int)eye] = new EyeRenderDesc() + { + resolution = new Vector2(1024, 1024), + fov = new Vector2(90, 90) + }; +#endif + } + + private void ConfigureEyeTexture(int eyeBufferIndex, OVREye eye, float scale) + { + int eyeIndex = eyeBufferIndex + (int)eye; + + EyeRenderDesc eyeDesc = eyeDescs[(int)eye]; + + int w = (int)(eyeDesc.resolution.x * scale); + int h = (int)(eyeDesc.resolution.y * scale); + + eyeTextures[eyeIndex] = new RenderTexture(w, h, OVRManager.instance.eyeTextureDepth, OVRManager.instance.eyeTextureFormat); + eyeTextures[eyeIndex].antiAliasing = (QualitySettings.antiAliasing == 0) ? 1 : QualitySettings.antiAliasing; + eyeTextures[eyeIndex].Create(); + eyeTextureIds[eyeIndex] = eyeTextures[eyeIndex].GetNativeTextureID(); + } + + public void ForceSymmetricProj(bool enabled) + { +#if !UNITY_ANDROID || UNITY_EDITOR + OVR_ForceSymmetricProj(enabled); +#endif + } + + public void SetViewport(int x, int y, int w, int h) + { +#if !UNITY_ANDROID || UNITY_EDITOR + OVR_SetViewport(x, y, w, h); +#endif + } + + private const string LibOVR = "OculusPlugin"; + +#if UNITY_ANDROID && !UNITY_EDITOR + //TODO: Get rid of these functions and implement OVR.CAPI.Hmd on Android. + + [DllImport(LibOVR)] + private static extern bool OVR_ResetSensorOrientation(); + [DllImport(LibOVR)] + private static extern bool OVR_GetAcceleration(ref float x, ref float y, ref float z); + [DllImport(LibOVR)] + private static extern bool OVR_GetAngularVelocity(ref float x, ref float y, ref float z); + [DllImport(LibOVR)] + private static extern bool OVR_IsHMDPresent(); + [DllImport(LibOVR)] + private static extern bool OVR_GetCameraPositionOrientation( + ref float px, + ref float py, + ref float pz, + ref float ox, + ref float oy, + ref float oz, + ref float ow, + double atTime); + [DllImport(LibOVR)] + private static extern void OVR_GetDistortionMeshInfo( + ref int resH, + ref int resV, + ref float fovH, + ref float fovV); + [DllImport(LibOVR)] + private static extern void OVR_SetLowPersistenceMode(bool on); + [DllImport(LibOVR)] + private static extern bool OVR_GetSensorState( + bool monoscopic, + ref float w, + ref float x, + ref float y, + ref float z, + ref float fov, + ref int viewNumber); +#else + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_SetDistortionCaps(uint distortionCaps); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern bool OVR_SetViewport(int x, int y, int w, int h); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern Posef OVR_GetRenderPose(int frameIndex, int eyeId); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern bool OVR_SetTexture(int id, System.IntPtr texture, float scale = 1); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern bool OVR_UnityGetModeChange(); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern bool OVR_UnitySetModeChange(bool isChanged); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_ForceSymmetricProj(bool isEnabled); +#endif +}