Initialer Upload neues Unity-Projekt
This commit is contained in:
792
Assets/SteamVR/Scripts/SteamVR.cs
Normal file
792
Assets/SteamVR/Scripts/SteamVR.cs
Normal file
@ -0,0 +1,792 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Access to SteamVR system (hmd) and compositor (distort) interfaces.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
using UnityEngine.XR;
|
||||
#else
|
||||
using XRSettings = UnityEngine.VR.VRSettings;
|
||||
using XRDevice = UnityEngine.VR.VRDevice;
|
||||
#endif
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR : System.IDisposable
|
||||
{
|
||||
// Use this to check if SteamVR is currently active without attempting
|
||||
// to activate it in the process.
|
||||
public static bool active { get { return _instance != null; } }
|
||||
|
||||
private static bool? isSupported = null;
|
||||
|
||||
// Set this to false to keep from auto-initializing when calling SteamVR.instance.
|
||||
private static bool _enabled = true;
|
||||
public static bool enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_enabled)
|
||||
{
|
||||
#if UNITY_2020_1_OR_NEWER || OPENVR_XR_API
|
||||
if (isSupported == null)
|
||||
{
|
||||
string[] supportedDevices = XRSettings.supportedDevices;
|
||||
for (int index = 0; index < supportedDevices.Length; index++)
|
||||
{
|
||||
if (supportedDevices[index].Contains("OpenVR"))
|
||||
{
|
||||
isSupported = true;
|
||||
}
|
||||
}
|
||||
if (isSupported == null)
|
||||
{
|
||||
isSupported = false;
|
||||
}
|
||||
}
|
||||
return isSupported.Value;
|
||||
#else
|
||||
return XRSettings.enabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
_enabled = value;
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
SafeDispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SteamVR _instance;
|
||||
public static SteamVR instance
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
return null;
|
||||
#endif
|
||||
if (!enabled)
|
||||
return null;
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = CreateInstance();
|
||||
|
||||
// If init failed, then auto-disable so scripts don't continue trying to re-initialize things.
|
||||
if (_instance == null)
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public enum InitializedStates
|
||||
{
|
||||
None,
|
||||
Initializing,
|
||||
InitializeSuccess,
|
||||
InitializeFailure,
|
||||
}
|
||||
|
||||
public static InitializedStates initializedState = InitializedStates.None;
|
||||
|
||||
public static void Initialize(bool forceUnityVRMode = false)
|
||||
{
|
||||
if (forceUnityVRMode)
|
||||
{
|
||||
SteamVR_Behaviour.instance.InitializeSteamVR(true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = CreateInstance();
|
||||
if (_instance == null)
|
||||
_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_enabled)
|
||||
SteamVR_Behaviour.Initialize(forceUnityVRMode);
|
||||
}
|
||||
|
||||
public static bool usingNativeSupport
|
||||
{
|
||||
get { return XRDevice.GetNativePtr() != System.IntPtr.Zero; }
|
||||
}
|
||||
|
||||
public static SteamVR_Settings settings { get; private set; }
|
||||
|
||||
private static void ReportGeneralErrors()
|
||||
{
|
||||
string errorLog = "<b>[SteamVR]</b> Initialization failed. ";
|
||||
|
||||
#if OPENVR_XR_API
|
||||
errorLog += "Please verify that you have SteamVR installed, your hmd is functioning, and OpenVR Loader is checked in the XR Plugin Management section of Project Settings.";
|
||||
#else
|
||||
|
||||
if (XRSettings.enabled == false)
|
||||
errorLog += "VR may be disabled in player settings. Go to player settings in the editor and check the 'Virtual Reality Supported' checkbox'. ";
|
||||
if (XRSettings.supportedDevices != null && XRSettings.supportedDevices.Length > 0)
|
||||
{
|
||||
if (XRSettings.supportedDevices.Contains("OpenVR") == false)
|
||||
errorLog += "OpenVR is not in your list of supported virtual reality SDKs. Add it to the list in player settings. ";
|
||||
else if (XRSettings.supportedDevices.First().Contains("OpenVR") == false)
|
||||
errorLog += "OpenVR is not first in your list of supported virtual reality SDKs. <b>This is okay, but if you have an Oculus device plugged in, and Oculus above OpenVR in this list, it will try and use the Oculus SDK instead of OpenVR.</b> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorLog += "You have no SDKs in your Player Settings list of supported virtual reality SDKs. Add OpenVR to it. ";
|
||||
}
|
||||
|
||||
errorLog += "To attempt to force OpenVR initialization call SteamVR.Initialize(true). ";
|
||||
#endif
|
||||
|
||||
Debug.LogWarning(errorLog);
|
||||
}
|
||||
|
||||
private static SteamVR CreateInstance()
|
||||
{
|
||||
initializedState = InitializedStates.Initializing;
|
||||
|
||||
try
|
||||
{
|
||||
var error = EVRInitError.None;
|
||||
|
||||
#if !OPENVR_XR_API
|
||||
if (!SteamVR.usingNativeSupport)
|
||||
{
|
||||
ReportGeneralErrors();
|
||||
initializedState = InitializedStates.InitializeFailure;
|
||||
SteamVR_Events.Initialized.Send(false);
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Verify common interfaces are valid.
|
||||
|
||||
OpenVR.GetGenericInterface(OpenVR.IVRCompositor_Version, ref error);
|
||||
if (error != EVRInitError.None)
|
||||
{
|
||||
initializedState = InitializedStates.InitializeFailure;
|
||||
ReportError(error);
|
||||
ReportGeneralErrors();
|
||||
SteamVR_Events.Initialized.Send(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
OpenVR.GetGenericInterface(OpenVR.IVROverlay_Version, ref error);
|
||||
if (error != EVRInitError.None)
|
||||
{
|
||||
initializedState = InitializedStates.InitializeFailure;
|
||||
ReportError(error);
|
||||
SteamVR_Events.Initialized.Send(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
OpenVR.GetGenericInterface(OpenVR.IVRInput_Version, ref error);
|
||||
if (error != EVRInitError.None)
|
||||
{
|
||||
initializedState = InitializedStates.InitializeFailure;
|
||||
ReportError(error);
|
||||
SteamVR_Events.Initialized.Send(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
settings = SteamVR_Settings.instance;
|
||||
|
||||
#if !OPENVR_XR_API
|
||||
if (Application.isEditor)
|
||||
IdentifyEditorApplication();
|
||||
|
||||
SteamVR_Input.IdentifyActionsFile();
|
||||
#endif
|
||||
|
||||
if (SteamVR_Settings.instance.inputUpdateMode != SteamVR_UpdateModes.Nothing || SteamVR_Settings.instance.poseUpdateMode != SteamVR_UpdateModes.Nothing)
|
||||
{
|
||||
SteamVR_Input.Initialize();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (SteamVR_Input.IsOpeningSetup())
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> " + e);
|
||||
SteamVR_Events.Initialized.Send(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
_enabled = true;
|
||||
initializedState = InitializedStates.InitializeSuccess;
|
||||
SteamVR_Events.Initialized.Send(true);
|
||||
return new SteamVR();
|
||||
}
|
||||
|
||||
static void ReportError(EVRInitError error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case EVRInitError.None:
|
||||
break;
|
||||
case EVRInitError.VendorSpecific_UnableToConnectToOculusRuntime:
|
||||
Debug.LogWarning("<b>[SteamVR]</b> Initialization Failed! Make sure device is on, Oculus runtime is installed, and OVRService_*.exe is running.");
|
||||
break;
|
||||
case EVRInitError.Init_VRClientDLLNotFound:
|
||||
Debug.LogWarning("<b>[SteamVR]</b> Drivers not found! They can be installed via Steam under Library > Tools. Visit http://steampowered.com to install Steam.");
|
||||
break;
|
||||
case EVRInitError.Driver_RuntimeOutOfDate:
|
||||
Debug.LogWarning("<b>[SteamVR]</b> Initialization Failed! Make sure device's runtime is up to date.");
|
||||
break;
|
||||
default:
|
||||
Debug.LogWarning("<b>[SteamVR]</b> " + OpenVR.GetStringForHmdError(error));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// native interfaces
|
||||
public CVRSystem hmd { get; private set; }
|
||||
public CVRCompositor compositor { get; private set; }
|
||||
public CVROverlay overlay { get; private set; }
|
||||
|
||||
// tracking status
|
||||
static public bool initializing { get; private set; }
|
||||
static public bool calibrating { get; private set; }
|
||||
static public bool outOfRange { get; private set; }
|
||||
|
||||
static public bool[] connected = new bool[OpenVR.k_unMaxTrackedDeviceCount];
|
||||
|
||||
// render values
|
||||
public float sceneWidth { get; private set; }
|
||||
public float sceneHeight { get; private set; }
|
||||
public float aspect { get; private set; }
|
||||
public float fieldOfView { get; private set; }
|
||||
public Vector2 tanHalfFov { get; private set; }
|
||||
public VRTextureBounds_t[] textureBounds { get; private set; }
|
||||
public SteamVR_Utils.RigidTransform[] eyes { get; private set; }
|
||||
public ETextureType textureType;
|
||||
|
||||
// hmd properties
|
||||
public string hmd_TrackingSystemName { get { return GetStringProperty(ETrackedDeviceProperty.Prop_TrackingSystemName_String); } }
|
||||
public string hmd_ModelNumber { get { return GetStringProperty(ETrackedDeviceProperty.Prop_ModelNumber_String); } }
|
||||
public string hmd_SerialNumber { get { return GetStringProperty(ETrackedDeviceProperty.Prop_SerialNumber_String); } }
|
||||
public string hmd_Type { get { return GetStringProperty(ETrackedDeviceProperty.Prop_ControllerType_String); } }
|
||||
|
||||
public float hmd_SecondsFromVsyncToPhotons { get { return GetFloatProperty(ETrackedDeviceProperty.Prop_SecondsFromVsyncToPhotons_Float); } }
|
||||
public float hmd_DisplayFrequency { get { return GetFloatProperty(ETrackedDeviceProperty.Prop_DisplayFrequency_Float); } }
|
||||
|
||||
public EDeviceActivityLevel GetHeadsetActivityLevel()
|
||||
{
|
||||
return OpenVR.System.GetTrackedDeviceActivityLevel(OpenVR.k_unTrackedDeviceIndex_Hmd);
|
||||
}
|
||||
|
||||
public string GetTrackedDeviceString(uint deviceId)
|
||||
{
|
||||
var error = ETrackedPropertyError.TrackedProp_Success;
|
||||
var capacity = hmd.GetStringTrackedDeviceProperty(deviceId, ETrackedDeviceProperty.Prop_AttachedDeviceId_String, null, 0, ref error);
|
||||
if (capacity > 1)
|
||||
{
|
||||
var result = new System.Text.StringBuilder((int)capacity);
|
||||
hmd.GetStringTrackedDeviceProperty(deviceId, ETrackedDeviceProperty.Prop_AttachedDeviceId_String, result, capacity, ref error);
|
||||
return result.ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetStringProperty(ETrackedDeviceProperty prop, uint deviceId = OpenVR.k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
var error = ETrackedPropertyError.TrackedProp_Success;
|
||||
var capactiy = hmd.GetStringTrackedDeviceProperty(deviceId, prop, null, 0, ref error);
|
||||
if (capactiy > 1)
|
||||
{
|
||||
var result = new System.Text.StringBuilder((int)capactiy);
|
||||
hmd.GetStringTrackedDeviceProperty(deviceId, prop, result, capactiy, ref error);
|
||||
return result.ToString();
|
||||
}
|
||||
return (error != ETrackedPropertyError.TrackedProp_Success) ? error.ToString() : "<unknown>";
|
||||
}
|
||||
|
||||
public float GetFloatProperty(ETrackedDeviceProperty prop, uint deviceId = OpenVR.k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
var error = ETrackedPropertyError.TrackedProp_Success;
|
||||
return hmd.GetFloatTrackedDeviceProperty(deviceId, prop, ref error);
|
||||
}
|
||||
|
||||
|
||||
private static bool runningTemporarySession = false;
|
||||
public static bool InitializeTemporarySession(bool initInput = false)
|
||||
{
|
||||
if (Application.isEditor)
|
||||
{
|
||||
//bool needsInit = (!active && !usingNativeSupport && !runningTemporarySession);
|
||||
|
||||
EVRInitError initError = EVRInitError.None;
|
||||
OpenVR.GetGenericInterface(OpenVR.IVRCompositor_Version, ref initError);
|
||||
bool needsInit = initError != EVRInitError.None;
|
||||
|
||||
if (needsInit)
|
||||
{
|
||||
EVRInitError error = EVRInitError.None;
|
||||
OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
|
||||
|
||||
if (error != EVRInitError.None)
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Error during OpenVR Init: " + error.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
IdentifyEditorApplication(false);
|
||||
|
||||
SteamVR_Input.IdentifyActionsFile(false);
|
||||
|
||||
runningTemporarySession = true;
|
||||
}
|
||||
|
||||
if (initInput)
|
||||
{
|
||||
SteamVR_Input.Initialize(true);
|
||||
}
|
||||
|
||||
return needsInit;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void ExitTemporarySession()
|
||||
{
|
||||
if (runningTemporarySession)
|
||||
{
|
||||
OpenVR.Shutdown();
|
||||
runningTemporarySession = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static void ShowBindingsForEditor()
|
||||
{
|
||||
bool temporarySession = InitializeTemporarySession(false);
|
||||
|
||||
|
||||
Valve.VR.EVRSettingsError bindingFlagError = Valve.VR.EVRSettingsError.None;
|
||||
Valve.VR.OpenVR.Settings.SetBool(Valve.VR.OpenVR.k_pch_SteamVR_Section, Valve.VR.OpenVR.k_pch_SteamVR_DebugInputBinding, true, ref bindingFlagError);
|
||||
|
||||
if (bindingFlagError != Valve.VR.EVRSettingsError.None)
|
||||
Debug.LogError("<b>[SteamVR]</b> Error turning on the debug input binding flag in steamvr: " + bindingFlagError.ToString());
|
||||
|
||||
if (Application.isPlaying == false)
|
||||
{
|
||||
IdentifyEditorApplication();
|
||||
|
||||
SteamVR_Input.IdentifyActionsFile();
|
||||
}
|
||||
|
||||
OpenVR.Input.OpenBindingUI(SteamVR_Settings.instance.editorAppKey, 0, 0, true);
|
||||
|
||||
if (temporarySession)
|
||||
ExitTemporarySession();
|
||||
}
|
||||
|
||||
public static string GetSteamVRFolderParentPath(bool localToAssetsFolder = false)
|
||||
{
|
||||
SteamVR_Settings asset = ScriptableObject.CreateInstance<SteamVR_Settings>();
|
||||
UnityEditor.MonoScript scriptAsset = UnityEditor.MonoScript.FromScriptableObject(asset);
|
||||
|
||||
string scriptPath = UnityEditor.AssetDatabase.GetAssetPath(scriptAsset);
|
||||
|
||||
System.IO.FileInfo settingsScriptFileInfo = new System.IO.FileInfo(scriptPath);
|
||||
|
||||
string fullPath = settingsScriptFileInfo.Directory.Parent.Parent.FullName;
|
||||
|
||||
if (localToAssetsFolder == false)
|
||||
return fullPath;
|
||||
else
|
||||
{
|
||||
System.IO.DirectoryInfo assetsDirectoryInfo = new DirectoryInfo(Application.dataPath);
|
||||
string localPath = fullPath.Substring(assetsDirectoryInfo.Parent.FullName.Length + 1); //plus separator char
|
||||
return localPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSteamVRFolderPath(bool localToAssetsFolder = false)
|
||||
{
|
||||
SteamVR_Settings asset = ScriptableObject.CreateInstance<SteamVR_Settings>();
|
||||
UnityEditor.MonoScript scriptAsset = UnityEditor.MonoScript.FromScriptableObject(asset);
|
||||
|
||||
string scriptPath = UnityEditor.AssetDatabase.GetAssetPath(scriptAsset);
|
||||
|
||||
System.IO.FileInfo settingsScriptFileInfo = new System.IO.FileInfo(scriptPath);
|
||||
string fullPath = settingsScriptFileInfo.Directory.Parent.FullName;
|
||||
|
||||
|
||||
if (localToAssetsFolder == false)
|
||||
return fullPath;
|
||||
else
|
||||
{
|
||||
System.IO.DirectoryInfo assetsDirectoryInfo = new DirectoryInfo(Application.dataPath);
|
||||
string localPath = fullPath.Substring(assetsDirectoryInfo.Parent.FullName.Length + 1); //plus separator char
|
||||
return localPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSteamVRResourcesFolderPath(bool localToAssetsFolder = false)
|
||||
{
|
||||
string basePath = GetSteamVRFolderParentPath(localToAssetsFolder);
|
||||
|
||||
string folderPath = Path.Combine(basePath, "SteamVR_Resources");
|
||||
|
||||
if (Directory.Exists(folderPath) == false)
|
||||
Directory.CreateDirectory(folderPath);
|
||||
|
||||
string resourcesFolderPath = Path.Combine(folderPath, "Resources");
|
||||
|
||||
if (Directory.Exists(resourcesFolderPath) == false)
|
||||
Directory.CreateDirectory(resourcesFolderPath);
|
||||
|
||||
return resourcesFolderPath;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public const string defaultUnityAppKeyTemplate = "application.generated.unity.{0}.exe";
|
||||
public const string defaultAppKeyTemplate = "application.generated.{0}";
|
||||
|
||||
public static string GenerateAppKey()
|
||||
{
|
||||
string productName = GenerateCleanProductName();
|
||||
|
||||
return string.Format(defaultUnityAppKeyTemplate, productName);
|
||||
}
|
||||
|
||||
public static string GenerateCleanProductName()
|
||||
{
|
||||
string productName = Application.productName;
|
||||
if (string.IsNullOrEmpty(productName))
|
||||
productName = "unnamed_product";
|
||||
else
|
||||
{
|
||||
productName = System.Text.RegularExpressions.Regex.Replace(Application.productName, "[^\\w\\._]", "");
|
||||
productName = productName.ToLower();
|
||||
}
|
||||
|
||||
return productName;
|
||||
}
|
||||
|
||||
private static string GetManifestFile()
|
||||
{
|
||||
string currentPath = Application.dataPath;
|
||||
int lastIndex = currentPath.LastIndexOf('/');
|
||||
currentPath = currentPath.Remove(lastIndex, currentPath.Length - lastIndex);
|
||||
|
||||
string fullPath = Path.Combine(currentPath, "unityProject.vrmanifest");
|
||||
|
||||
FileInfo fullManifestPath = new FileInfo(SteamVR_Input.GetActionsFilePath());
|
||||
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
string jsonText = File.ReadAllText(fullPath);
|
||||
SteamVR_Input_ManifestFile existingFile = Valve.Newtonsoft.Json.JsonConvert.DeserializeObject<SteamVR_Input_ManifestFile>(jsonText);
|
||||
|
||||
if (existingFile != null && existingFile.applications != null && existingFile.applications.Count > 0 &&
|
||||
existingFile.applications[0].app_key != SteamVR_Settings.instance.editorAppKey)
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> Deleting existing VRManifest because it has a different app key.");
|
||||
FileInfo existingInfo = new FileInfo(fullPath);
|
||||
if (existingInfo.IsReadOnly)
|
||||
existingInfo.IsReadOnly = false;
|
||||
existingInfo.Delete();
|
||||
}
|
||||
|
||||
if (existingFile != null && existingFile.applications != null && existingFile.applications.Count > 0 &&
|
||||
existingFile.applications[0].action_manifest_path != fullManifestPath.FullName)
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> Deleting existing VRManifest because it has a different action manifest path:" +
|
||||
"\nExisting:" + existingFile.applications[0].action_manifest_path +
|
||||
"\nNew: " + fullManifestPath.FullName);
|
||||
FileInfo existingInfo = new FileInfo(fullPath);
|
||||
if (existingInfo.IsReadOnly)
|
||||
existingInfo.IsReadOnly = false;
|
||||
existingInfo.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(fullPath) == false)
|
||||
{
|
||||
SteamVR_Input_ManifestFile manifestFile = new SteamVR_Input_ManifestFile();
|
||||
manifestFile.source = "Unity";
|
||||
SteamVR_Input_ManifestFile_Application manifestApplication = new SteamVR_Input_ManifestFile_Application();
|
||||
manifestApplication.app_key = SteamVR_Settings.instance.editorAppKey;
|
||||
manifestApplication.action_manifest_path = fullManifestPath.FullName;
|
||||
manifestApplication.launch_type = "url";
|
||||
//manifestApplication.binary_path_windows = SteamVR_Utils.ConvertToForwardSlashes(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
|
||||
//manifestApplication.binary_path_linux = SteamVR_Utils.ConvertToForwardSlashes(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
|
||||
//manifestApplication.binary_path_osx = SteamVR_Utils.ConvertToForwardSlashes(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
|
||||
manifestApplication.url = "steam://launch/";
|
||||
manifestApplication.strings.Add("en_us", new SteamVR_Input_ManifestFile_ApplicationString() { name = string.Format("{0} [Testing]", Application.productName) });
|
||||
|
||||
/*
|
||||
var bindings = new System.Collections.Generic.List<SteamVR_Input_ManifestFile_Application_Binding>();
|
||||
|
||||
SteamVR_Input.InitializeFile();
|
||||
if (SteamVR_Input.actionFile != null)
|
||||
{
|
||||
string[] bindingFiles = SteamVR_Input.actionFile.GetFilesToCopy(true);
|
||||
if (bindingFiles.Length == SteamVR_Input.actionFile.default_bindings.Count)
|
||||
{
|
||||
for (int bindingIndex = 0; bindingIndex < bindingFiles.Length; bindingIndex++)
|
||||
{
|
||||
SteamVR_Input_ManifestFile_Application_Binding binding = new SteamVR_Input_ManifestFile_Application_Binding();
|
||||
binding.binding_url = bindingFiles[bindingIndex];
|
||||
binding.controller_type = SteamVR_Input.actionFile.default_bindings[bindingIndex].controller_type;
|
||||
bindings.Add(binding);
|
||||
}
|
||||
manifestApplication.bindings = bindings;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Mismatch in available binding files.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Could not load actions file.");
|
||||
}
|
||||
*/
|
||||
|
||||
manifestFile.applications = new System.Collections.Generic.List<SteamVR_Input_ManifestFile_Application>();
|
||||
manifestFile.applications.Add(manifestApplication);
|
||||
|
||||
string json = Valve.Newtonsoft.Json.JsonConvert.SerializeObject(manifestFile, Valve.Newtonsoft.Json.Formatting.Indented,
|
||||
new Valve.Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Valve.Newtonsoft.Json.NullValueHandling.Ignore });
|
||||
|
||||
File.WriteAllText(fullPath, json);
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
private static void IdentifyEditorApplication(bool showLogs = true)
|
||||
{
|
||||
//bool isInstalled = OpenVR.Applications.IsApplicationInstalled(SteamVR_Settings.instance.editorAppKey);
|
||||
|
||||
if (string.IsNullOrEmpty(SteamVR_Settings.instance.editorAppKey))
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Critical Error identifying application. EditorAppKey is null or empty. Input may not work.");
|
||||
return;
|
||||
}
|
||||
|
||||
string manifestPath = GetManifestFile();
|
||||
|
||||
EVRApplicationError addManifestErr = OpenVR.Applications.AddApplicationManifest(manifestPath, true);
|
||||
if (addManifestErr != EVRApplicationError.None)
|
||||
Debug.LogError("<b>[SteamVR]</b> Error adding vr manifest file: " + addManifestErr.ToString());
|
||||
else
|
||||
{
|
||||
if (showLogs)
|
||||
Debug.Log("<b>[SteamVR]</b> Successfully added VR manifest to SteamVR");
|
||||
}
|
||||
|
||||
int processId = System.Diagnostics.Process.GetCurrentProcess().Id;
|
||||
EVRApplicationError applicationIdentifyErr = OpenVR.Applications.IdentifyApplication((uint)processId, SteamVR_Settings.instance.editorAppKey);
|
||||
|
||||
if (applicationIdentifyErr != EVRApplicationError.None)
|
||||
Debug.LogError("<b>[SteamVR]</b> Error identifying application: " + applicationIdentifyErr.ToString());
|
||||
else
|
||||
{
|
||||
if (showLogs)
|
||||
Debug.Log(string.Format("<b>[SteamVR]</b> Successfully identified process as editor project to SteamVR ({0})", SteamVR_Settings.instance.editorAppKey));
|
||||
}
|
||||
}
|
||||
|
||||
#region Event callbacks
|
||||
|
||||
private void OnInitializing(bool initializing)
|
||||
{
|
||||
SteamVR.initializing = initializing;
|
||||
}
|
||||
|
||||
private void OnCalibrating(bool calibrating)
|
||||
{
|
||||
SteamVR.calibrating = calibrating;
|
||||
}
|
||||
|
||||
private void OnOutOfRange(bool outOfRange)
|
||||
{
|
||||
SteamVR.outOfRange = outOfRange;
|
||||
}
|
||||
|
||||
private void OnDeviceConnected(int i, bool connected)
|
||||
{
|
||||
SteamVR.connected[i] = connected;
|
||||
}
|
||||
|
||||
private void OnNewPoses(TrackedDevicePose_t[] poses)
|
||||
{
|
||||
// Update eye offsets to account for IPD changes.
|
||||
eyes[0] = new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Left));
|
||||
eyes[1] = new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Right));
|
||||
|
||||
for (int i = 0; i < poses.Length; i++)
|
||||
{
|
||||
var connected = poses[i].bDeviceIsConnected;
|
||||
if (connected != SteamVR.connected[i])
|
||||
{
|
||||
SteamVR_Events.DeviceConnected.Send(i, connected);
|
||||
}
|
||||
}
|
||||
|
||||
if (poses.Length > OpenVR.k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
var result = poses[OpenVR.k_unTrackedDeviceIndex_Hmd].eTrackingResult;
|
||||
|
||||
var initializing = result == ETrackingResult.Uninitialized;
|
||||
if (initializing != SteamVR.initializing)
|
||||
{
|
||||
SteamVR_Events.Initializing.Send(initializing);
|
||||
}
|
||||
|
||||
var calibrating =
|
||||
result == ETrackingResult.Calibrating_InProgress ||
|
||||
result == ETrackingResult.Calibrating_OutOfRange;
|
||||
if (calibrating != SteamVR.calibrating)
|
||||
{
|
||||
SteamVR_Events.Calibrating.Send(calibrating);
|
||||
}
|
||||
|
||||
var outOfRange =
|
||||
result == ETrackingResult.Running_OutOfRange ||
|
||||
result == ETrackingResult.Calibrating_OutOfRange;
|
||||
if (outOfRange != SteamVR.outOfRange)
|
||||
{
|
||||
SteamVR_Events.OutOfRange.Send(outOfRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private SteamVR()
|
||||
{
|
||||
hmd = OpenVR.System;
|
||||
Debug.LogFormat("<b>[SteamVR]</b> Initialized. Connected to {0} : {1} : {2} :: {3}", hmd_TrackingSystemName, hmd_ModelNumber, hmd_SerialNumber, hmd_Type);
|
||||
|
||||
compositor = OpenVR.Compositor;
|
||||
overlay = OpenVR.Overlay;
|
||||
|
||||
// Setup render values
|
||||
uint w = 0, h = 0;
|
||||
hmd.GetRecommendedRenderTargetSize(ref w, ref h);
|
||||
sceneWidth = (float)w;
|
||||
sceneHeight = (float)h;
|
||||
|
||||
float l_left = 0.0f, l_right = 0.0f, l_top = 0.0f, l_bottom = 0.0f;
|
||||
hmd.GetProjectionRaw(EVREye.Eye_Left, ref l_left, ref l_right, ref l_top, ref l_bottom);
|
||||
|
||||
float r_left = 0.0f, r_right = 0.0f, r_top = 0.0f, r_bottom = 0.0f;
|
||||
hmd.GetProjectionRaw(EVREye.Eye_Right, ref r_left, ref r_right, ref r_top, ref r_bottom);
|
||||
|
||||
tanHalfFov = new Vector2(
|
||||
Mathf.Max(-l_left, l_right, -r_left, r_right),
|
||||
Mathf.Max(-l_top, l_bottom, -r_top, r_bottom));
|
||||
|
||||
textureBounds = new VRTextureBounds_t[2];
|
||||
|
||||
textureBounds[0].uMin = 0.5f + 0.5f * l_left / tanHalfFov.x;
|
||||
textureBounds[0].uMax = 0.5f + 0.5f * l_right / tanHalfFov.x;
|
||||
textureBounds[0].vMin = 0.5f - 0.5f * l_bottom / tanHalfFov.y;
|
||||
textureBounds[0].vMax = 0.5f - 0.5f * l_top / tanHalfFov.y;
|
||||
|
||||
textureBounds[1].uMin = 0.5f + 0.5f * r_left / tanHalfFov.x;
|
||||
textureBounds[1].uMax = 0.5f + 0.5f * r_right / tanHalfFov.x;
|
||||
textureBounds[1].vMin = 0.5f - 0.5f * r_bottom / tanHalfFov.y;
|
||||
textureBounds[1].vMax = 0.5f - 0.5f * r_top / tanHalfFov.y;
|
||||
|
||||
// Grow the recommended size to account for the overlapping fov
|
||||
sceneWidth = sceneWidth / Mathf.Max(textureBounds[0].uMax - textureBounds[0].uMin, textureBounds[1].uMax - textureBounds[1].uMin);
|
||||
sceneHeight = sceneHeight / Mathf.Max(textureBounds[0].vMax - textureBounds[0].vMin, textureBounds[1].vMax - textureBounds[1].vMin);
|
||||
|
||||
aspect = tanHalfFov.x / tanHalfFov.y;
|
||||
fieldOfView = 2.0f * Mathf.Atan(tanHalfFov.y) * Mathf.Rad2Deg;
|
||||
|
||||
eyes = new SteamVR_Utils.RigidTransform[] {
|
||||
new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Left)),
|
||||
new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Right)) };
|
||||
|
||||
switch (SystemInfo.graphicsDeviceType)
|
||||
{
|
||||
#if (UNITY_5_4)
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.OpenGL2:
|
||||
#endif
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.OpenGLCore:
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.OpenGLES2:
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.OpenGLES3:
|
||||
textureType = ETextureType.OpenGL;
|
||||
break;
|
||||
#if !(UNITY_5_4)
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.Vulkan:
|
||||
textureType = ETextureType.Vulkan;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
textureType = ETextureType.DirectX;
|
||||
break;
|
||||
}
|
||||
|
||||
SteamVR_Events.Initializing.Listen(OnInitializing);
|
||||
SteamVR_Events.Calibrating.Listen(OnCalibrating);
|
||||
SteamVR_Events.OutOfRange.Listen(OnOutOfRange);
|
||||
SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected);
|
||||
SteamVR_Events.NewPoses.Listen(OnNewPoses);
|
||||
}
|
||||
|
||||
~SteamVR()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
System.GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
SteamVR_Events.Initializing.Remove(OnInitializing);
|
||||
SteamVR_Events.Calibrating.Remove(OnCalibrating);
|
||||
SteamVR_Events.OutOfRange.Remove(OnOutOfRange);
|
||||
SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected);
|
||||
SteamVR_Events.NewPoses.Remove(OnNewPoses);
|
||||
|
||||
_instance = null;
|
||||
}
|
||||
|
||||
// Use this interface to avoid accidentally creating the instance in the process of attempting to dispose of it.
|
||||
public static void SafeDispose()
|
||||
{
|
||||
if (_instance != null)
|
||||
_instance.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fae0ddab09ac324c85494471274d6a4
|
||||
timeCreated: 1544852182
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
259
Assets/SteamVR/Scripts/SteamVR_Behaviour.cs
Normal file
259
Assets/SteamVR/Scripts/SteamVR_Behaviour.cs
Normal file
@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
using UnityEngine.XR;
|
||||
#else
|
||||
using XRSettings = UnityEngine.VR.VRSettings;
|
||||
using XRDevice = UnityEngine.VR.VRDevice;
|
||||
#endif
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Behaviour : MonoBehaviour
|
||||
{
|
||||
private const string openVRDeviceName = "OpenVR";
|
||||
public static bool forcingInitialization = false;
|
||||
|
||||
private static SteamVR_Behaviour _instance;
|
||||
public static SteamVR_Behaviour instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
Initialize(false);
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public bool initializeSteamVROnAwake = true;
|
||||
|
||||
public bool doNotDestroy = true;
|
||||
|
||||
[HideInInspector]
|
||||
public SteamVR_Render steamvr_render;
|
||||
|
||||
internal static bool isPlaying = false;
|
||||
|
||||
private static bool initializing = false;
|
||||
public static void Initialize(bool forceUnityVRToOpenVR = false)
|
||||
{
|
||||
if (_instance == null && initializing == false)
|
||||
{
|
||||
initializing = true;
|
||||
GameObject steamVRObject = null;
|
||||
|
||||
if (forceUnityVRToOpenVR)
|
||||
forcingInitialization = true;
|
||||
|
||||
SteamVR_Render renderInstance = GameObject.FindObjectOfType<SteamVR_Render>();
|
||||
if (renderInstance != null)
|
||||
steamVRObject = renderInstance.gameObject;
|
||||
|
||||
SteamVR_Behaviour behaviourInstance = GameObject.FindObjectOfType<SteamVR_Behaviour>();
|
||||
if (behaviourInstance != null)
|
||||
steamVRObject = behaviourInstance.gameObject;
|
||||
|
||||
if (steamVRObject == null)
|
||||
{
|
||||
GameObject objectInstance = new GameObject("[SteamVR]");
|
||||
_instance = objectInstance.AddComponent<SteamVR_Behaviour>();
|
||||
_instance.steamvr_render = objectInstance.AddComponent<SteamVR_Render>();
|
||||
}
|
||||
else
|
||||
{
|
||||
behaviourInstance = steamVRObject.GetComponent<SteamVR_Behaviour>();
|
||||
if (behaviourInstance == null)
|
||||
behaviourInstance = steamVRObject.AddComponent<SteamVR_Behaviour>();
|
||||
|
||||
if (renderInstance != null)
|
||||
behaviourInstance.steamvr_render = renderInstance;
|
||||
else
|
||||
{
|
||||
behaviourInstance.steamvr_render = steamVRObject.GetComponent<SteamVR_Render>();
|
||||
if (behaviourInstance.steamvr_render == null)
|
||||
behaviourInstance.steamvr_render = steamVRObject.AddComponent<SteamVR_Render>();
|
||||
}
|
||||
|
||||
_instance = behaviourInstance;
|
||||
}
|
||||
|
||||
if (_instance != null && _instance.doNotDestroy)
|
||||
GameObject.DontDestroyOnLoad(_instance.transform.root.gameObject);
|
||||
|
||||
initializing = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void Awake()
|
||||
{
|
||||
isPlaying = true;
|
||||
|
||||
if (initializeSteamVROnAwake && forcingInitialization == false)
|
||||
InitializeSteamVR();
|
||||
}
|
||||
|
||||
public void InitializeSteamVR(bool forceUnityVRToOpenVR = false)
|
||||
{
|
||||
if (forceUnityVRToOpenVR)
|
||||
{
|
||||
forcingInitialization = true;
|
||||
|
||||
if (initializeCoroutine != null)
|
||||
StopCoroutine(initializeCoroutine);
|
||||
|
||||
if (XRSettings.loadedDeviceName == openVRDeviceName)
|
||||
EnableOpenVR();
|
||||
else
|
||||
initializeCoroutine = StartCoroutine(DoInitializeSteamVR(forceUnityVRToOpenVR));
|
||||
}
|
||||
else
|
||||
{
|
||||
SteamVR.Initialize(false);
|
||||
}
|
||||
}
|
||||
|
||||
private Coroutine initializeCoroutine;
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
private bool loadedOpenVRDeviceSuccess = false;
|
||||
private IEnumerator DoInitializeSteamVR(bool forceUnityVRToOpenVR = false)
|
||||
{
|
||||
XRDevice.deviceLoaded += XRDevice_deviceLoaded;
|
||||
XRSettings.LoadDeviceByName(openVRDeviceName);
|
||||
while (loadedOpenVRDeviceSuccess == false)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
XRDevice.deviceLoaded -= XRDevice_deviceLoaded;
|
||||
EnableOpenVR();
|
||||
}
|
||||
|
||||
private void XRDevice_deviceLoaded(string deviceName)
|
||||
{
|
||||
if (deviceName == openVRDeviceName)
|
||||
{
|
||||
loadedOpenVRDeviceSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Tried to async load: " + openVRDeviceName + ". Loaded: " + deviceName, this);
|
||||
loadedOpenVRDeviceSuccess = true; //try anyway
|
||||
}
|
||||
}
|
||||
#else
|
||||
private IEnumerator DoInitializeSteamVR(bool forceUnityVRToOpenVR = false)
|
||||
{
|
||||
XRSettings.LoadDeviceByName(openVRDeviceName);
|
||||
yield return null;
|
||||
EnableOpenVR();
|
||||
}
|
||||
#endif
|
||||
|
||||
private void EnableOpenVR()
|
||||
{
|
||||
XRSettings.enabled = true;
|
||||
SteamVR.Initialize(false);
|
||||
initializeCoroutine = null;
|
||||
forcingInitialization = false;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
//only stop playing if the unity editor is running
|
||||
private void OnDestroy()
|
||||
{
|
||||
isPlaying = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
protected void OnEnable()
|
||||
{
|
||||
Application.onBeforeRender += OnBeforeRender;
|
||||
SteamVR_Events.System(EVREventType.VREvent_Quit).Listen(OnQuit);
|
||||
}
|
||||
protected void OnDisable()
|
||||
{
|
||||
Application.onBeforeRender -= OnBeforeRender;
|
||||
SteamVR_Events.System(EVREventType.VREvent_Quit).Remove(OnQuit);
|
||||
}
|
||||
protected void OnBeforeRender()
|
||||
{
|
||||
PreCull();
|
||||
}
|
||||
#else
|
||||
protected void OnEnable()
|
||||
{
|
||||
Camera.onPreCull += OnCameraPreCull;
|
||||
SteamVR_Events.System(EVREventType.VREvent_Quit).Listen(OnQuit);
|
||||
}
|
||||
protected void OnDisable()
|
||||
{
|
||||
Camera.onPreCull -= OnCameraPreCull;
|
||||
SteamVR_Events.System(EVREventType.VREvent_Quit).Remove(OnQuit);
|
||||
}
|
||||
protected void OnCameraPreCull(Camera cam)
|
||||
{
|
||||
if (!cam.stereoEnabled)
|
||||
return;
|
||||
|
||||
PreCull();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected static int lastFrameCount = -1;
|
||||
protected void PreCull()
|
||||
{
|
||||
if (OpenVR.Input != null)
|
||||
{
|
||||
// Only update poses on the first camera per frame.
|
||||
if (Time.frameCount != lastFrameCount)
|
||||
{
|
||||
lastFrameCount = Time.frameCount;
|
||||
|
||||
SteamVR_Input.OnPreCull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void FixedUpdate()
|
||||
{
|
||||
if (OpenVR.Input != null)
|
||||
{
|
||||
SteamVR_Input.FixedUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void LateUpdate()
|
||||
{
|
||||
if (OpenVR.Input != null)
|
||||
{
|
||||
SteamVR_Input.LateUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void Update()
|
||||
{
|
||||
if (OpenVR.Input != null)
|
||||
{
|
||||
SteamVR_Input.Update();
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnQuit(VREvent_t vrEvent)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Behaviour.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Behaviour.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1aaa8a3afb932fe478757c1e89cf0cd5
|
||||
timeCreated: 1544852184
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -31900
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
294
Assets/SteamVR/Scripts/SteamVR_Camera.cs
Normal file
294
Assets/SteamVR/Scripts/SteamVR_Camera.cs
Normal file
@ -0,0 +1,294 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Adds SteamVR render support to existing camera objects
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Valve.VR;
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
using UnityEngine.XR;
|
||||
#else
|
||||
using XRSettings = UnityEngine.VR.VRSettings;
|
||||
using XRDevice = UnityEngine.VR.VRDevice;
|
||||
#endif
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[RequireComponent(typeof(Camera))]
|
||||
public class SteamVR_Camera : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private Transform _head;
|
||||
public Transform head { get { return _head; } }
|
||||
public Transform offset { get { return _head; } } // legacy
|
||||
public Transform origin { get { return _head.parent; } }
|
||||
|
||||
public new Camera camera { get; private set; }
|
||||
|
||||
[SerializeField]
|
||||
private Transform _ears;
|
||||
public Transform ears { get { return _ears; } }
|
||||
|
||||
public Ray GetRay()
|
||||
{
|
||||
return new Ray(_head.position, _head.forward);
|
||||
}
|
||||
|
||||
public bool wireframe = false;
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
static public float sceneResolutionScale
|
||||
{
|
||||
get { return XRSettings.eyeTextureResolutionScale; }
|
||||
set { XRSettings.eyeTextureResolutionScale = value; }
|
||||
}
|
||||
#else
|
||||
static public float sceneResolutionScale
|
||||
{
|
||||
get { return XRSettings.renderScale; }
|
||||
set { if (value == 0) return; XRSettings.renderScale = value; }
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Enable / Disable
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
SteamVR_Render.Remove(this);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Bail if no hmd is connected
|
||||
var vr = SteamVR.instance;
|
||||
if (vr == null)
|
||||
{
|
||||
if (head != null)
|
||||
{
|
||||
head.GetComponent<SteamVR_TrackedObject>().enabled = false;
|
||||
}
|
||||
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert camera rig for native OpenVR integration.
|
||||
var t = transform;
|
||||
if (head != t)
|
||||
{
|
||||
Expand();
|
||||
|
||||
t.parent = origin;
|
||||
|
||||
while (head.childCount > 0)
|
||||
head.GetChild(0).parent = t;
|
||||
|
||||
// Keep the head around, but parent to the camera now since it moves with the hmd
|
||||
// but existing content may still have references to this object.
|
||||
head.parent = t;
|
||||
head.localPosition = Vector3.zero;
|
||||
head.localRotation = Quaternion.identity;
|
||||
head.localScale = Vector3.one;
|
||||
head.gameObject.SetActive(false);
|
||||
|
||||
_head = t;
|
||||
}
|
||||
|
||||
if (ears == null)
|
||||
{
|
||||
var e = transform.GetComponentInChildren<SteamVR_Ears>();
|
||||
if (e != null)
|
||||
_ears = e.transform;
|
||||
}
|
||||
|
||||
if (ears != null)
|
||||
ears.GetComponent<SteamVR_Ears>().vrcam = this;
|
||||
|
||||
SteamVR_Render.Add(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functionality to ensure SteamVR_Camera component is always the last component on an object
|
||||
|
||||
void Awake()
|
||||
{
|
||||
camera = GetComponent<Camera>(); // cached to avoid runtime lookup
|
||||
ForceLast();
|
||||
}
|
||||
|
||||
static Hashtable values;
|
||||
|
||||
public void ForceLast()
|
||||
{
|
||||
if (values != null)
|
||||
{
|
||||
// Restore values on new instance
|
||||
foreach (DictionaryEntry entry in values)
|
||||
{
|
||||
var f = entry.Key as FieldInfo;
|
||||
f.SetValue(this, entry.Value);
|
||||
}
|
||||
values = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure it's the last component
|
||||
var components = GetComponents<Component>();
|
||||
|
||||
// But first make sure there aren't any other SteamVR_Cameras on this object.
|
||||
for (int i = 0; i < components.Length; i++)
|
||||
{
|
||||
var c = components[i] as SteamVR_Camera;
|
||||
if (c != null && c != this)
|
||||
{
|
||||
DestroyImmediate(c);
|
||||
}
|
||||
}
|
||||
|
||||
components = GetComponents<Component>();
|
||||
|
||||
if (this != components[components.Length - 1])
|
||||
{
|
||||
// Store off values to be restored on new instance
|
||||
values = new Hashtable();
|
||||
var fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
foreach (var f in fields)
|
||||
if (f.IsPublic || f.IsDefined(typeof(SerializeField), true))
|
||||
values[f] = f.GetValue(this);
|
||||
|
||||
var go = gameObject;
|
||||
DestroyImmediate(this);
|
||||
go.AddComponent<SteamVR_Camera>().ForceLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Expand / Collapse object hierarchy
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public bool isExpanded { get { return head != null && transform.parent == head; } }
|
||||
#endif
|
||||
const string eyeSuffix = " (eye)";
|
||||
const string earsSuffix = " (ears)";
|
||||
const string headSuffix = " (head)";
|
||||
const string originSuffix = " (origin)";
|
||||
public string baseName { get { return name.EndsWith(eyeSuffix) ? name.Substring(0, name.Length - eyeSuffix.Length) : name; } }
|
||||
|
||||
// Object hierarchy creation to make it easy to parent other objects appropriately,
|
||||
// otherwise this gets called on demand at runtime. Remaining initialization is
|
||||
// performed at startup, once the hmd has been identified.
|
||||
public void Expand()
|
||||
{
|
||||
var _origin = transform.parent;
|
||||
if (_origin == null)
|
||||
{
|
||||
_origin = new GameObject(name + originSuffix).transform;
|
||||
_origin.localPosition = transform.localPosition;
|
||||
_origin.localRotation = transform.localRotation;
|
||||
_origin.localScale = transform.localScale;
|
||||
}
|
||||
|
||||
if (head == null)
|
||||
{
|
||||
_head = new GameObject(name + headSuffix, typeof(SteamVR_TrackedObject)).transform;
|
||||
head.parent = _origin;
|
||||
head.position = transform.position;
|
||||
head.rotation = transform.rotation;
|
||||
head.localScale = Vector3.one;
|
||||
head.tag = tag;
|
||||
}
|
||||
|
||||
if (transform.parent != head)
|
||||
{
|
||||
transform.parent = head;
|
||||
transform.localPosition = Vector3.zero;
|
||||
transform.localRotation = Quaternion.identity;
|
||||
transform.localScale = Vector3.one;
|
||||
|
||||
while (transform.childCount > 0)
|
||||
transform.GetChild(0).parent = head;
|
||||
#if !UNITY_2017_2_OR_NEWER
|
||||
var guiLayer = GetComponent<GUILayer>();
|
||||
if (guiLayer != null)
|
||||
{
|
||||
DestroyImmediate(guiLayer);
|
||||
head.gameObject.AddComponent<GUILayer>();
|
||||
}
|
||||
#endif
|
||||
var audioListener = GetComponent<AudioListener>();
|
||||
if (audioListener != null)
|
||||
{
|
||||
DestroyImmediate(audioListener);
|
||||
_ears = new GameObject(name + earsSuffix, typeof(SteamVR_Ears)).transform;
|
||||
ears.parent = _head;
|
||||
ears.localPosition = Vector3.zero;
|
||||
ears.localRotation = Quaternion.identity;
|
||||
ears.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
if (!name.EndsWith(eyeSuffix))
|
||||
name += eyeSuffix;
|
||||
}
|
||||
|
||||
public void Collapse()
|
||||
{
|
||||
transform.parent = null;
|
||||
|
||||
// Move children and components from head back to camera.
|
||||
while (head.childCount > 0)
|
||||
head.GetChild(0).parent = transform;
|
||||
#if !UNITY_2017_2_OR_NEWER
|
||||
var guiLayer = head.GetComponent<GUILayer>();
|
||||
if (guiLayer != null)
|
||||
{
|
||||
DestroyImmediate(guiLayer);
|
||||
gameObject.AddComponent<GUILayer>();
|
||||
}
|
||||
#endif
|
||||
if (ears != null)
|
||||
{
|
||||
while (ears.childCount > 0)
|
||||
ears.GetChild(0).parent = transform;
|
||||
|
||||
DestroyImmediate(ears.gameObject);
|
||||
_ears = null;
|
||||
|
||||
gameObject.AddComponent(typeof(AudioListener));
|
||||
}
|
||||
|
||||
if (origin != null)
|
||||
{
|
||||
// If we created the origin originally, destroy it now.
|
||||
if (origin.name.EndsWith(originSuffix))
|
||||
{
|
||||
// Reparent any children so we don't accidentally delete them.
|
||||
var _origin = origin;
|
||||
while (_origin.childCount > 0)
|
||||
_origin.GetChild(0).parent = _origin.parent;
|
||||
|
||||
DestroyImmediate(_origin.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.parent = origin;
|
||||
}
|
||||
}
|
||||
|
||||
DestroyImmediate(head.gameObject);
|
||||
_head = null;
|
||||
|
||||
if (name.EndsWith(eyeSuffix))
|
||||
name = name.Substring(0, name.Length - eyeSuffix.Length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Camera.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Camera.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bca9ccf900ccc84c887d783321d27e2
|
||||
timeCreated: 1544852185
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -31700
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
20
Assets/SteamVR/Scripts/SteamVR_CameraFlip.cs
Normal file
20
Assets/SteamVR/Scripts/SteamVR_CameraFlip.cs
Normal file
@ -0,0 +1,20 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Flips the camera output back to normal for D3D.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class SteamVR_CameraFlip : MonoBehaviour
|
||||
{
|
||||
void Awake()
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> SteamVR_CameraFlip is deprecated in Unity 5.4 - REMOVING");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_CameraFlip.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_CameraFlip.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5be45115742b07478e21c85fcc233ec
|
||||
timeCreated: 1544852186
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
20
Assets/SteamVR/Scripts/SteamVR_CameraMask.cs
Normal file
20
Assets/SteamVR/Scripts/SteamVR_CameraMask.cs
Normal file
@ -0,0 +1,20 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Masks out pixels that cannot be seen through the connected hmd.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class SteamVR_CameraMask : MonoBehaviour
|
||||
{
|
||||
void Awake()
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> SteamVR_CameraMask is deprecated in Unity 5.4 - REMOVING");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_CameraMask.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_CameraMask.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5828f252c3c228f4b931f66c21e525c4
|
||||
timeCreated: 1544852186
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
54
Assets/SteamVR/Scripts/SteamVR_Ears.cs
Normal file
54
Assets/SteamVR/Scripts/SteamVR_Ears.cs
Normal file
@ -0,0 +1,54 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Handles aligning audio listener when using speakers.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[RequireComponent(typeof(AudioListener))]
|
||||
public class SteamVR_Ears : MonoBehaviour
|
||||
{
|
||||
public SteamVR_Camera vrcam;
|
||||
|
||||
bool usingSpeakers;
|
||||
Quaternion offset;
|
||||
|
||||
private void OnNewPosesApplied()
|
||||
{
|
||||
var origin = vrcam.origin;
|
||||
var baseRotation = origin != null ? origin.rotation : Quaternion.identity;
|
||||
transform.rotation = baseRotation * offset;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
usingSpeakers = false;
|
||||
|
||||
var settings = OpenVR.Settings;
|
||||
if (settings != null)
|
||||
{
|
||||
var error = EVRSettingsError.None;
|
||||
if (settings.GetBool(OpenVR.k_pch_SteamVR_Section, OpenVR.k_pch_SteamVR_UsingSpeakers_Bool, ref error))
|
||||
{
|
||||
usingSpeakers = true;
|
||||
|
||||
var yawOffset = settings.GetFloat(OpenVR.k_pch_SteamVR_Section, OpenVR.k_pch_SteamVR_SpeakersForwardYawOffsetDegrees_Float, ref error);
|
||||
offset = Quaternion.Euler(0.0f, yawOffset, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (usingSpeakers)
|
||||
SteamVR_Events.NewPosesApplied.Listen(OnNewPosesApplied);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (usingSpeakers)
|
||||
SteamVR_Events.NewPosesApplied.Remove(OnNewPosesApplied);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Ears.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Ears.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49a86c1078ce4314b9c4224560e031b9
|
||||
timeCreated: 1544852186
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
Assets/SteamVR/Scripts/SteamVR_EnumEqualityComparer.cs
Normal file
52
Assets/SteamVR/Scripts/SteamVR_EnumEqualityComparer.cs
Normal file
@ -0,0 +1,52 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
struct SteamVREnumEqualityComparer<TEnum> : IEqualityComparer<TEnum> where TEnum : struct
|
||||
{
|
||||
static class BoxAvoidance
|
||||
{
|
||||
static readonly Func<TEnum, int> _wrapper;
|
||||
|
||||
public static int ToInt(TEnum enu)
|
||||
{
|
||||
return _wrapper(enu);
|
||||
}
|
||||
|
||||
static BoxAvoidance()
|
||||
{
|
||||
var p = Expression.Parameter(typeof(TEnum), null);
|
||||
var c = Expression.ConvertChecked(p, typeof(int));
|
||||
|
||||
_wrapper = Expression.Lambda<Func<TEnum, int>>(c, p).Compile();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(TEnum firstEnum, TEnum secondEnum)
|
||||
{
|
||||
return BoxAvoidance.ToInt(firstEnum) == BoxAvoidance.ToInt(secondEnum);
|
||||
}
|
||||
|
||||
public int GetHashCode(TEnum firstEnum)
|
||||
{
|
||||
return BoxAvoidance.ToInt(firstEnum);
|
||||
}
|
||||
}
|
||||
|
||||
public struct SteamVR_Input_Sources_Comparer : IEqualityComparer<SteamVR_Input_Sources>
|
||||
{
|
||||
public bool Equals(SteamVR_Input_Sources x, SteamVR_Input_Sources y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
public int GetHashCode(SteamVR_Input_Sources obj)
|
||||
{
|
||||
return (int)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_EnumEqualityComparer.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_EnumEqualityComparer.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c871825e556a1f140a5118ccf59e64d2
|
||||
timeCreated: 1544852186
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
208
Assets/SteamVR/Scripts/SteamVR_Events.cs
Normal file
208
Assets/SteamVR/Scripts/SteamVR_Events.cs
Normal file
@ -0,0 +1,208 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Simple event system for SteamVR.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// void OnDeviceConnected(int i, bool connected) { ... }
|
||||
// SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected); // Usually in OnEnable
|
||||
// SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected); // Usually in OnDisable
|
||||
//
|
||||
// Alternatively, if Listening/Removing often these can be cached as follows:
|
||||
//
|
||||
// SteamVR_Event.Action deviceConnectedAction;
|
||||
// void OnAwake() { deviceConnectedAction = SteamVR_Event.DeviceConnectedAction(OnDeviceConnected); }
|
||||
// void OnEnable() { deviceConnectedAction.enabled = true; }
|
||||
// void OnDisable() { deviceConnectedAction.enabled = false; }
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public static class SteamVR_Events
|
||||
{
|
||||
public abstract class Action
|
||||
{
|
||||
public abstract void Enable(bool enabled);
|
||||
public bool enabled { set { Enable(value); } }
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class ActionNoArgs : Action
|
||||
{
|
||||
public ActionNoArgs(Event _event, UnityAction action)
|
||||
{
|
||||
this._event = _event;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public override void Enable(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
_event.Listen(action);
|
||||
else
|
||||
_event.Remove(action);
|
||||
}
|
||||
|
||||
Event _event;
|
||||
UnityAction action;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class Action<T> : Action
|
||||
{
|
||||
public Action(Event<T> _event, UnityAction<T> action)
|
||||
{
|
||||
this._event = _event;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public override void Enable(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
_event.Listen(action);
|
||||
else
|
||||
_event.Remove(action);
|
||||
}
|
||||
|
||||
Event<T> _event;
|
||||
UnityAction<T> action;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class Action<T0, T1> : Action
|
||||
{
|
||||
public Action(Event<T0, T1> _event, UnityAction<T0, T1> action)
|
||||
{
|
||||
this._event = _event;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public override void Enable(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
_event.Listen(action);
|
||||
else
|
||||
_event.Remove(action);
|
||||
}
|
||||
|
||||
Event<T0, T1> _event;
|
||||
UnityAction<T0, T1> action;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class Action<T0, T1, T2> : Action
|
||||
{
|
||||
public Action(Event<T0, T1, T2> _event, UnityAction<T0, T1, T2> action)
|
||||
{
|
||||
this._event = _event;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public override void Enable(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
_event.Listen(action);
|
||||
else
|
||||
_event.Remove(action);
|
||||
}
|
||||
|
||||
Event<T0, T1, T2> _event;
|
||||
UnityAction<T0, T1, T2> action;
|
||||
}
|
||||
|
||||
public class Event : UnityEvent
|
||||
{
|
||||
public void Listen(UnityAction action) { this.AddListener(action); }
|
||||
public void Remove(UnityAction action) { this.RemoveListener(action); }
|
||||
public void Send() { this.Invoke(); }
|
||||
}
|
||||
|
||||
public class Event<T> : UnityEvent<T>
|
||||
{
|
||||
public void Listen(UnityAction<T> action) { this.AddListener(action); }
|
||||
public void Remove(UnityAction<T> action) { this.RemoveListener(action); }
|
||||
public void Send(T arg0) { this.Invoke(arg0); }
|
||||
}
|
||||
|
||||
public class Event<T0, T1> : UnityEvent<T0, T1>
|
||||
{
|
||||
public void Listen(UnityAction<T0, T1> action) { this.AddListener(action); }
|
||||
public void Remove(UnityAction<T0, T1> action) { this.RemoveListener(action); }
|
||||
public void Send(T0 arg0, T1 arg1) { this.Invoke(arg0, arg1); }
|
||||
}
|
||||
|
||||
public class Event<T0, T1, T2> : UnityEvent<T0, T1, T2>
|
||||
{
|
||||
public void Listen(UnityAction<T0, T1, T2> action) { this.AddListener(action); }
|
||||
public void Remove(UnityAction<T0, T1, T2> action) { this.RemoveListener(action); }
|
||||
public void Send(T0 arg0, T1 arg1, T2 arg2) { this.Invoke(arg0, arg1, arg2); }
|
||||
}
|
||||
|
||||
public static Event<bool> Calibrating = new Event<bool>();
|
||||
public static Action CalibratingAction(UnityAction<bool> action) { return new Action<bool>(Calibrating, action); }
|
||||
|
||||
public static Event<int, bool> DeviceConnected = new Event<int, bool>();
|
||||
public static Action DeviceConnectedAction(UnityAction<int, bool> action) { return new Action<int, bool>(DeviceConnected, action); }
|
||||
|
||||
public static Event<Color, float, bool> Fade = new Event<Color, float, bool>();
|
||||
public static Action FadeAction(UnityAction<Color, float, bool> action) { return new Action<Color, float, bool>(Fade, action); }
|
||||
|
||||
public static Event FadeReady = new Event();
|
||||
public static Action FadeReadyAction(UnityAction action) { return new ActionNoArgs(FadeReady, action); }
|
||||
|
||||
public static Event<bool> HideRenderModels = new Event<bool>();
|
||||
public static Action HideRenderModelsAction(UnityAction<bool> action) { return new Action<bool>(HideRenderModels, action); }
|
||||
|
||||
public static Event<bool> Initializing = new Event<bool>();
|
||||
public static Action InitializingAction(UnityAction<bool> action) { return new Action<bool>(Initializing, action); }
|
||||
|
||||
public static Event<bool> InputFocus = new Event<bool>();
|
||||
public static Action InputFocusAction(UnityAction<bool> action) { return new Action<bool>(InputFocus, action); }
|
||||
|
||||
public static Event<bool> Loading = new Event<bool>();
|
||||
public static Action LoadingAction(UnityAction<bool> action) { return new Action<bool>(Loading, action); }
|
||||
|
||||
public static Event<float> LoadingFadeIn = new Event<float>();
|
||||
public static Action LoadingFadeInAction(UnityAction<float> action) { return new Action<float>(LoadingFadeIn, action); }
|
||||
|
||||
public static Event<float> LoadingFadeOut = new Event<float>();
|
||||
public static Action LoadingFadeOutAction(UnityAction<float> action) { return new Action<float>(LoadingFadeOut, action); }
|
||||
|
||||
public static Event<TrackedDevicePose_t[]> NewPoses = new Event<TrackedDevicePose_t[]>();
|
||||
public static Action NewPosesAction(UnityAction<TrackedDevicePose_t[]> action) { return new Action<TrackedDevicePose_t[]>(NewPoses, action); }
|
||||
|
||||
public static Event NewPosesApplied = new Event();
|
||||
public static Action NewPosesAppliedAction(UnityAction action) { return new ActionNoArgs(NewPosesApplied, action); }
|
||||
|
||||
public static Event<bool> Initialized = new Event<bool>();
|
||||
public static Action InitializedAction(UnityAction<bool> action) { return new Action<bool>(Initialized, action); }
|
||||
|
||||
public static Event<bool> OutOfRange = new Event<bool>();
|
||||
public static Action OutOfRangeAction(UnityAction<bool> action) { return new Action<bool>(OutOfRange, action); }
|
||||
|
||||
public static Event<SteamVR_RenderModel, bool> RenderModelLoaded = new Event<SteamVR_RenderModel, bool>();
|
||||
public static Action RenderModelLoadedAction(UnityAction<SteamVR_RenderModel, bool> action) { return new Action<SteamVR_RenderModel, bool>(RenderModelLoaded, action); }
|
||||
|
||||
static System.Collections.Generic.Dictionary<EVREventType, Event<VREvent_t>> systemEvents = new System.Collections.Generic.Dictionary<EVREventType, Event<VREvent_t>>();
|
||||
public static Event<VREvent_t> System(EVREventType eventType)
|
||||
{
|
||||
Event<VREvent_t> e;
|
||||
if (!systemEvents.TryGetValue(eventType, out e))
|
||||
{
|
||||
e = new Event<VREvent_t>();
|
||||
systemEvents.Add(eventType, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
public static Action SystemAction(EVREventType eventType, UnityAction<VREvent_t> action)
|
||||
{
|
||||
return new Action<VREvent_t>(System(eventType), action);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Events.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Events.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44cb57742f235524189e5d8af1c4f3cc
|
||||
timeCreated: 1544852186
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
433
Assets/SteamVR/Scripts/SteamVR_ExternalCamera.cs
Normal file
433
Assets/SteamVR/Scripts/SteamVR_ExternalCamera.cs
Normal file
@ -0,0 +1,433 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Used to render an external camera of vr player (split front/back).
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_ExternalCamera : MonoBehaviour
|
||||
{
|
||||
private SteamVR_Action_Pose cameraPose = null;
|
||||
private SteamVR_Input_Sources cameraInputSource = SteamVR_Input_Sources.Camera;
|
||||
|
||||
[System.Serializable]
|
||||
public struct Config
|
||||
{
|
||||
public float x, y, z;
|
||||
public float rx, ry, rz;
|
||||
public float fov;
|
||||
public float near, far;
|
||||
public float sceneResolutionScale;
|
||||
public float frameSkip;
|
||||
public float nearOffset, farOffset;
|
||||
public float hmdOffset;
|
||||
public float r, g, b, a; // chroma key override
|
||||
public bool disableStandardAssets;
|
||||
}
|
||||
|
||||
[Space()]
|
||||
public Config config;
|
||||
public string configPath;
|
||||
|
||||
[Tooltip("This will automatically activate the action set the specified pose belongs to. And deactivate it when this component is disabled.")]
|
||||
public bool autoEnableDisableActionSet = true;
|
||||
|
||||
public void ReadConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
var mCam = new HmdMatrix34_t();
|
||||
var readCamMatrix = false;
|
||||
|
||||
object c = config; // box
|
||||
var lines = System.IO.File.ReadAllLines(configPath);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var split = line.Split('=');
|
||||
if (split.Length == 2)
|
||||
{
|
||||
var key = split[0];
|
||||
if (key == "m")
|
||||
{
|
||||
var values = split[1].Split(',');
|
||||
if (values.Length == 12)
|
||||
{
|
||||
mCam.m0 = float.Parse(values[0]);
|
||||
mCam.m1 = float.Parse(values[1]);
|
||||
mCam.m2 = float.Parse(values[2]);
|
||||
mCam.m3 = float.Parse(values[3]);
|
||||
mCam.m4 = float.Parse(values[4]);
|
||||
mCam.m5 = float.Parse(values[5]);
|
||||
mCam.m6 = float.Parse(values[6]);
|
||||
mCam.m7 = float.Parse(values[7]);
|
||||
mCam.m8 = float.Parse(values[8]);
|
||||
mCam.m9 = float.Parse(values[9]);
|
||||
mCam.m10 = float.Parse(values[10]);
|
||||
mCam.m11 = float.Parse(values[11]);
|
||||
readCamMatrix = true;
|
||||
}
|
||||
}
|
||||
#if !UNITY_METRO
|
||||
else if (key == "disableStandardAssets")
|
||||
{
|
||||
var field = c.GetType().GetField(key);
|
||||
if (field != null)
|
||||
field.SetValue(c, bool.Parse(split[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
var field = c.GetType().GetField(key);
|
||||
if (field != null)
|
||||
field.SetValue(c, float.Parse(split[1]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
config = (Config)c; //unbox
|
||||
|
||||
// Convert calibrated camera matrix settings.
|
||||
if (readCamMatrix)
|
||||
{
|
||||
var t = new SteamVR_Utils.RigidTransform(mCam);
|
||||
config.x = t.pos.x;
|
||||
config.y = t.pos.y;
|
||||
config.z = t.pos.z;
|
||||
var angles = t.rot.eulerAngles;
|
||||
config.rx = angles.x;
|
||||
config.ry = angles.y;
|
||||
config.rz = angles.z;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Clear target so AttachToCamera gets called to pick up any changes.
|
||||
target = null;
|
||||
#if !UNITY_METRO
|
||||
// Listen for changes.
|
||||
if (watcher == null)
|
||||
{
|
||||
var fi = new System.IO.FileInfo(configPath);
|
||||
watcher = new System.IO.FileSystemWatcher(fi.DirectoryName, fi.Name);
|
||||
watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite;
|
||||
watcher.Changed += new System.IO.FileSystemEventHandler(OnChanged);
|
||||
watcher.EnableRaisingEvents = true;
|
||||
}
|
||||
}
|
||||
|
||||
System.IO.FileSystemWatcher watcher;
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
|
||||
public void SetupPose(SteamVR_Action_Pose newCameraPose, SteamVR_Input_Sources newCameraSource)
|
||||
{
|
||||
cameraPose = newCameraPose;
|
||||
cameraInputSource = newCameraSource;
|
||||
|
||||
AutoEnableActionSet();
|
||||
|
||||
SteamVR_Behaviour_Pose poseBehaviour = this.gameObject.AddComponent<SteamVR_Behaviour_Pose>();
|
||||
poseBehaviour.poseAction = newCameraPose;
|
||||
poseBehaviour.inputSource = newCameraSource;
|
||||
}
|
||||
|
||||
public void SetupDeviceIndex(int deviceIndex)
|
||||
{
|
||||
SteamVR_TrackedObject trackedObject = this.gameObject.AddComponent<SteamVR_TrackedObject>();
|
||||
trackedObject.SetDeviceIndex(deviceIndex);
|
||||
}
|
||||
|
||||
void OnChanged(object source, System.IO.FileSystemEventArgs e)
|
||||
{
|
||||
ReadConfig();
|
||||
}
|
||||
|
||||
Camera cam;
|
||||
Transform target;
|
||||
GameObject clipQuad;
|
||||
Material clipMaterial;
|
||||
|
||||
protected SteamVR_ActionSet activatedActionSet;
|
||||
protected SteamVR_Input_Sources activatedInputSource;
|
||||
public void AttachToCamera(SteamVR_Camera steamVR_Camera)
|
||||
{
|
||||
Camera vrcam;
|
||||
if (steamVR_Camera == null)
|
||||
{
|
||||
vrcam = Camera.main;
|
||||
|
||||
if (target == vrcam.transform)
|
||||
return;
|
||||
target = vrcam.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
vrcam = steamVR_Camera.camera;
|
||||
|
||||
if (target == steamVR_Camera.head)
|
||||
return;
|
||||
target = steamVR_Camera.head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var root = transform.parent;
|
||||
var origin = target.parent;
|
||||
root.parent = origin;
|
||||
root.localPosition = Vector3.zero;
|
||||
root.localRotation = Quaternion.identity;
|
||||
root.localScale = Vector3.one;
|
||||
|
||||
// Make a copy of the eye camera to pick up any camera fx.
|
||||
vrcam.enabled = false;
|
||||
var go = Instantiate(vrcam.gameObject);
|
||||
vrcam.enabled = true;
|
||||
go.name = "camera";
|
||||
|
||||
DestroyImmediate(go.GetComponent<SteamVR_Camera>());
|
||||
DestroyImmediate(go.GetComponent<SteamVR_Fade>());
|
||||
|
||||
cam = go.GetComponent<Camera>();
|
||||
cam.stereoTargetEye = StereoTargetEyeMask.None;
|
||||
cam.fieldOfView = config.fov;
|
||||
cam.useOcclusionCulling = false;
|
||||
cam.enabled = false; // manually rendered
|
||||
cam.rect = new Rect(0, 0, 1, 1); //fix order of operations issue
|
||||
|
||||
colorMat = new Material(Shader.Find("Custom/SteamVR_ColorOut"));
|
||||
alphaMat = new Material(Shader.Find("Custom/SteamVR_AlphaOut"));
|
||||
clipMaterial = new Material(Shader.Find("Custom/SteamVR_ClearAll"));
|
||||
|
||||
var offset = go.transform;
|
||||
offset.parent = transform;
|
||||
offset.localPosition = new Vector3(config.x, config.y, config.z);
|
||||
offset.localRotation = Quaternion.Euler(config.rx, config.ry, config.rz);
|
||||
offset.localScale = Vector3.one;
|
||||
|
||||
// Strip children of cloned object (AudioListener in particular).
|
||||
while (offset.childCount > 0)
|
||||
DestroyImmediate(offset.GetChild(0).gameObject);
|
||||
|
||||
// Setup clipping quad (using camera clip causes problems with shadows).
|
||||
clipQuad = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
||||
clipQuad.name = "ClipQuad";
|
||||
DestroyImmediate(clipQuad.GetComponent<MeshCollider>());
|
||||
|
||||
var clipRenderer = clipQuad.GetComponent<MeshRenderer>();
|
||||
clipRenderer.material = clipMaterial;
|
||||
clipRenderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||
clipRenderer.receiveShadows = false;
|
||||
clipRenderer.lightProbeUsage = LightProbeUsage.Off;
|
||||
clipRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
||||
|
||||
var clipTransform = clipQuad.transform;
|
||||
clipTransform.parent = offset;
|
||||
clipTransform.localScale = new Vector3(1000.0f, 1000.0f, 1.0f);
|
||||
clipTransform.localRotation = Quaternion.identity;
|
||||
|
||||
clipQuad.SetActive(false);
|
||||
}
|
||||
|
||||
public float GetTargetDistance()
|
||||
{
|
||||
if (target == null)
|
||||
return config.near + 0.01f;
|
||||
|
||||
var offset = cam.transform;
|
||||
var forward = new Vector3(offset.forward.x, 0.0f, offset.forward.z).normalized;
|
||||
var targetPos = target.position + new Vector3(target.forward.x, 0.0f, target.forward.z).normalized * config.hmdOffset;
|
||||
|
||||
var distance = -(new Plane(forward, targetPos)).GetDistanceToPoint(offset.position);
|
||||
return Mathf.Clamp(distance, config.near + 0.01f, config.far - 0.01f);
|
||||
}
|
||||
|
||||
Material colorMat, alphaMat;
|
||||
|
||||
public void RenderNear()
|
||||
{
|
||||
var w = Screen.width / 2;
|
||||
var h = Screen.height / 2;
|
||||
|
||||
if (cam.targetTexture == null || cam.targetTexture.width != w || cam.targetTexture.height != h)
|
||||
{
|
||||
var tex = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32);
|
||||
tex.antiAliasing = QualitySettings.antiAliasing == 0 ? 1 : QualitySettings.antiAliasing;
|
||||
cam.targetTexture = tex;
|
||||
}
|
||||
|
||||
cam.nearClipPlane = config.near;
|
||||
cam.farClipPlane = config.far;
|
||||
|
||||
var clearFlags = cam.clearFlags;
|
||||
var backgroundColor = cam.backgroundColor;
|
||||
|
||||
cam.clearFlags = CameraClearFlags.Color;
|
||||
cam.backgroundColor = Color.clear;
|
||||
|
||||
clipMaterial.color = new Color(config.r, config.g, config.b, config.a);
|
||||
|
||||
float dist = Mathf.Clamp(GetTargetDistance() + config.nearOffset, config.near, config.far);
|
||||
var clipParent = clipQuad.transform.parent;
|
||||
clipQuad.transform.position = clipParent.position + clipParent.forward * dist;
|
||||
|
||||
MonoBehaviour[] behaviours = null;
|
||||
bool[] wasEnabled = null;
|
||||
if (config.disableStandardAssets)
|
||||
{
|
||||
behaviours = cam.gameObject.GetComponents<MonoBehaviour>();
|
||||
wasEnabled = new bool[behaviours.Length];
|
||||
for (int i = 0; i < behaviours.Length; i++)
|
||||
{
|
||||
var behaviour = behaviours[i];
|
||||
if (behaviour.enabled && behaviour.GetType().ToString().StartsWith("UnityStandardAssets."))
|
||||
{
|
||||
behaviour.enabled = false;
|
||||
wasEnabled[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clipQuad.SetActive(true);
|
||||
|
||||
cam.Render();
|
||||
|
||||
Graphics.DrawTexture(new Rect(0, 0, w, h), cam.targetTexture, colorMat);
|
||||
|
||||
// Re-render scene with post-processing fx disabled (if necessary) since they override alpha.
|
||||
var pp = cam.gameObject.GetComponent("PostProcessingBehaviour") as MonoBehaviour;
|
||||
if ((pp != null) && pp.enabled)
|
||||
{
|
||||
pp.enabled = false;
|
||||
cam.Render();
|
||||
pp.enabled = true;
|
||||
}
|
||||
|
||||
Graphics.DrawTexture(new Rect(w, 0, w, h), cam.targetTexture, alphaMat);
|
||||
|
||||
// Restore settings.
|
||||
clipQuad.SetActive(false);
|
||||
|
||||
if (behaviours != null)
|
||||
{
|
||||
for (int i = 0; i < behaviours.Length; i++)
|
||||
{
|
||||
if (wasEnabled[i])
|
||||
{
|
||||
behaviours[i].enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cam.clearFlags = clearFlags;
|
||||
cam.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
public void RenderFar()
|
||||
{
|
||||
cam.nearClipPlane = config.near;
|
||||
cam.farClipPlane = config.far;
|
||||
cam.Render();
|
||||
|
||||
var w = Screen.width / 2;
|
||||
var h = Screen.height / 2;
|
||||
Graphics.DrawTexture(new Rect(0, h, w, h), cam.targetTexture, colorMat);
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
// Necessary for Graphics.DrawTexture to work even though we don't do anything here.
|
||||
}
|
||||
|
||||
Camera[] cameras;
|
||||
Rect[] cameraRects;
|
||||
float sceneResolutionScale;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Move game view cameras to lower-right quadrant.
|
||||
cameras = FindObjectsOfType<Camera>();
|
||||
if (cameras != null)
|
||||
{
|
||||
var numCameras = cameras.Length;
|
||||
cameraRects = new Rect[numCameras];
|
||||
for (int i = 0; i < numCameras; i++)
|
||||
{
|
||||
var cam = cameras[i];
|
||||
cameraRects[i] = cam.rect;
|
||||
|
||||
if (cam == this.cam)
|
||||
continue;
|
||||
|
||||
if (cam.targetTexture != null)
|
||||
continue;
|
||||
|
||||
if (cam.GetComponent<SteamVR_Camera>() != null)
|
||||
continue;
|
||||
|
||||
cam.rect = new Rect(0.5f, 0.0f, 0.5f, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.sceneResolutionScale > 0.0f)
|
||||
{
|
||||
sceneResolutionScale = SteamVR_Camera.sceneResolutionScale;
|
||||
SteamVR_Camera.sceneResolutionScale = config.sceneResolutionScale;
|
||||
}
|
||||
|
||||
AutoEnableActionSet();
|
||||
}
|
||||
|
||||
private void AutoEnableActionSet()
|
||||
{
|
||||
if (autoEnableDisableActionSet)
|
||||
{
|
||||
if (cameraPose != null)
|
||||
{
|
||||
if (cameraPose.actionSet.IsActive(cameraInputSource) == false)
|
||||
{
|
||||
activatedActionSet = cameraPose.actionSet; //automatically activate the actionset if it isn't active already. (will deactivate on component disable)
|
||||
activatedInputSource = cameraInputSource;
|
||||
cameraPose.actionSet.Activate(cameraInputSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (autoEnableDisableActionSet)
|
||||
{
|
||||
if (activatedActionSet != null) //deactivate the action set we activated for this camera
|
||||
{
|
||||
activatedActionSet.Deactivate(activatedInputSource);
|
||||
activatedActionSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Restore game view cameras.
|
||||
if (cameras != null)
|
||||
{
|
||||
var numCameras = cameras.Length;
|
||||
for (int i = 0; i < numCameras; i++)
|
||||
{
|
||||
var cam = cameras[i];
|
||||
if (cam != null)
|
||||
cam.rect = cameraRects[i];
|
||||
}
|
||||
cameras = null;
|
||||
cameraRects = null;
|
||||
}
|
||||
|
||||
if (config.sceneResolutionScale > 0.0f)
|
||||
{
|
||||
SteamVR_Camera.sceneResolutionScale = sceneResolutionScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_ExternalCamera.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_ExternalCamera.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9da270df5147d24597cc106058c1fa7
|
||||
timeCreated: 1544852187
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,52 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Used to render an external camera of vr player (split front/back).
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_ExternalCamera_LegacyManager
|
||||
{
|
||||
public static bool hasCamera { get { return cameraIndex != -1; } }
|
||||
|
||||
public static int cameraIndex = -1;
|
||||
|
||||
private static SteamVR_Events.Action newPosesAction = null;
|
||||
|
||||
public static void SubscribeToNewPoses()
|
||||
{
|
||||
if (newPosesAction == null)
|
||||
newPosesAction = SteamVR_Events.NewPosesAction(OnNewPoses);
|
||||
|
||||
newPosesAction.enabled = true;
|
||||
}
|
||||
|
||||
private static void OnNewPoses(TrackedDevicePose_t[] poses)
|
||||
{
|
||||
if (cameraIndex != -1)
|
||||
return;
|
||||
|
||||
int controllercount = 0;
|
||||
for (int index = 0; index < poses.Length; index++)
|
||||
{
|
||||
if (poses[index].bDeviceIsConnected)
|
||||
{
|
||||
ETrackedDeviceClass deviceClass = OpenVR.System.GetTrackedDeviceClass((uint)index);
|
||||
if (deviceClass == ETrackedDeviceClass.Controller || deviceClass == ETrackedDeviceClass.GenericTracker)
|
||||
{
|
||||
controllercount++;
|
||||
if (controllercount >= 3)
|
||||
{
|
||||
cameraIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7294a236dff50fc44b22361c6187a574
|
||||
timeCreated: 1560296085
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
129
Assets/SteamVR/Scripts/SteamVR_Fade.cs
Normal file
129
Assets/SteamVR/Scripts/SteamVR_Fade.cs
Normal file
@ -0,0 +1,129 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: CameraFade script adapted to work with SteamVR.
|
||||
//
|
||||
// Usage: Add to your top level SteamVR_Camera (the one with ApplyDistoration
|
||||
// checked) and drag a reference to this component into SteamVR_Camera
|
||||
// RenderComponents list. Then call the static helper function
|
||||
// SteamVR_Fade.Start with the desired color and duration.
|
||||
// Use a duration of zero to set the start color.
|
||||
//
|
||||
// Example: Fade down from black over one second.
|
||||
// SteamVR_Fade.Start(Color.black, 0);
|
||||
// SteamVR_Fade.Start(Color.clear, 1);
|
||||
//
|
||||
// Note: This component is provided to fade out a single camera layer's
|
||||
// scene view. If instead you want to fade the entire view, use:
|
||||
// SteamVR_Fade.View(Color.black, 1);
|
||||
// (Does not affect the game view, however.)
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Fade : MonoBehaviour
|
||||
{
|
||||
private Color currentColor = new Color(0, 0, 0, 0); // default starting color: black and fully transparent
|
||||
private Color targetColor = new Color(0, 0, 0, 0); // default target color: black and fully transparent
|
||||
private Color deltaColor = new Color(0, 0, 0, 0); // the delta-color is basically the "speed / second" at which the current color should change
|
||||
private bool fadeOverlay = false;
|
||||
|
||||
static public void Start(Color newColor, float duration, bool fadeOverlay = false)
|
||||
{
|
||||
SteamVR_Events.Fade.Send(newColor, duration, fadeOverlay);
|
||||
}
|
||||
|
||||
static public void View(Color newColor, float duration)
|
||||
{
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
compositor.FadeToColor(duration, newColor.r, newColor.g, newColor.b, newColor.a, false);
|
||||
}
|
||||
|
||||
#if TEST_FADE_VIEW
|
||||
void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Space))
|
||||
{
|
||||
SteamVR_Fade.View(Color.black, 0);
|
||||
SteamVR_Fade.View(Color.clear, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public void OnStartFade(Color newColor, float duration, bool fadeOverlay)
|
||||
{
|
||||
if (duration > 0.0f)
|
||||
{
|
||||
targetColor = newColor;
|
||||
deltaColor = (targetColor - currentColor) / duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentColor = newColor;
|
||||
}
|
||||
}
|
||||
|
||||
static Material fadeMaterial = null;
|
||||
static int fadeMaterialColorID = -1;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (fadeMaterial == null)
|
||||
{
|
||||
fadeMaterial = new Material(Shader.Find("Custom/SteamVR_Fade"));
|
||||
fadeMaterialColorID = Shader.PropertyToID("fadeColor");
|
||||
}
|
||||
|
||||
SteamVR_Events.Fade.Listen(OnStartFade);
|
||||
SteamVR_Events.FadeReady.Send();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
SteamVR_Events.Fade.Remove(OnStartFade);
|
||||
}
|
||||
|
||||
void OnPostRender()
|
||||
{
|
||||
if (currentColor != targetColor)
|
||||
{
|
||||
// if the difference between the current alpha and the desired alpha is smaller than delta-alpha * deltaTime, then we're pretty much done fading:
|
||||
if (Mathf.Abs(currentColor.a - targetColor.a) < Mathf.Abs(deltaColor.a) * Time.deltaTime)
|
||||
{
|
||||
currentColor = targetColor;
|
||||
deltaColor = new Color(0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentColor += deltaColor * Time.deltaTime;
|
||||
}
|
||||
|
||||
if (fadeOverlay)
|
||||
{
|
||||
var overlay = SteamVR_Overlay.instance;
|
||||
if (overlay != null)
|
||||
{
|
||||
overlay.alpha = 1.0f - currentColor.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentColor.a > 0 && fadeMaterial)
|
||||
{
|
||||
fadeMaterial.SetColor(fadeMaterialColorID, currentColor);
|
||||
fadeMaterial.SetPass(0);
|
||||
GL.Begin(GL.QUADS);
|
||||
|
||||
GL.Vertex3(-1, -1, 0);
|
||||
GL.Vertex3(1, -1, 0);
|
||||
GL.Vertex3(1, 1, 0);
|
||||
GL.Vertex3(-1, 1, 0);
|
||||
GL.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Fade.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Fade.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ad1e469d4e3e04489f9a36419f1a4f8
|
||||
timeCreated: 1544852187
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
154
Assets/SteamVR/Scripts/SteamVR_Frustum.cs
Normal file
154
Assets/SteamVR/Scripts/SteamVR_Frustum.cs
Normal file
@ -0,0 +1,154 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Generates a mesh based on field of view.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[ExecuteInEditMode, RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
|
||||
public class SteamVR_Frustum : MonoBehaviour
|
||||
{
|
||||
public SteamVR_TrackedObject.EIndex index;
|
||||
|
||||
public float fovLeft = 45, fovRight = 45, fovTop = 45, fovBottom = 45, nearZ = 0.5f, farZ = 2.5f;
|
||||
|
||||
public void UpdateModel()
|
||||
{
|
||||
fovLeft = Mathf.Clamp(fovLeft, 1, 89);
|
||||
fovRight = Mathf.Clamp(fovRight, 1, 89);
|
||||
fovTop = Mathf.Clamp(fovTop, 1, 89);
|
||||
fovBottom = Mathf.Clamp(fovBottom, 1, 89);
|
||||
farZ = Mathf.Max(farZ, nearZ + 0.01f);
|
||||
nearZ = Mathf.Clamp(nearZ, 0.01f, farZ - 0.01f);
|
||||
|
||||
var lsin = Mathf.Sin(-fovLeft * Mathf.Deg2Rad);
|
||||
var rsin = Mathf.Sin(fovRight * Mathf.Deg2Rad);
|
||||
var tsin = Mathf.Sin(fovTop * Mathf.Deg2Rad);
|
||||
var bsin = Mathf.Sin(-fovBottom * Mathf.Deg2Rad);
|
||||
|
||||
var lcos = Mathf.Cos(-fovLeft * Mathf.Deg2Rad);
|
||||
var rcos = Mathf.Cos(fovRight * Mathf.Deg2Rad);
|
||||
var tcos = Mathf.Cos(fovTop * Mathf.Deg2Rad);
|
||||
var bcos = Mathf.Cos(-fovBottom * Mathf.Deg2Rad);
|
||||
|
||||
var corners = new Vector3[] {
|
||||
new Vector3(lsin * nearZ / lcos, tsin * nearZ / tcos, nearZ), //tln
|
||||
new Vector3(rsin * nearZ / rcos, tsin * nearZ / tcos, nearZ), //trn
|
||||
new Vector3(rsin * nearZ / rcos, bsin * nearZ / bcos, nearZ), //brn
|
||||
new Vector3(lsin * nearZ / lcos, bsin * nearZ / bcos, nearZ), //bln
|
||||
new Vector3(lsin * farZ / lcos, tsin * farZ / tcos, farZ ), //tlf
|
||||
new Vector3(rsin * farZ / rcos, tsin * farZ / tcos, farZ ), //trf
|
||||
new Vector3(rsin * farZ / rcos, bsin * farZ / bcos, farZ ), //brf
|
||||
new Vector3(lsin * farZ / lcos, bsin * farZ / bcos, farZ ), //blf
|
||||
};
|
||||
|
||||
var triangles = new int[] {
|
||||
// 0, 1, 2, 0, 2, 3, // near
|
||||
// 0, 2, 1, 0, 3, 2, // near
|
||||
// 4, 5, 6, 4, 6, 7, // far
|
||||
// 4, 6, 5, 4, 7, 6, // far
|
||||
0, 4, 7, 0, 7, 3, // left
|
||||
0, 7, 4, 0, 3, 7, // left
|
||||
1, 5, 6, 1, 6, 2, // right
|
||||
1, 6, 5, 1, 2, 6, // right
|
||||
0, 4, 5, 0, 5, 1, // top
|
||||
0, 5, 4, 0, 1, 5, // top
|
||||
2, 3, 7, 2, 7, 6, // bottom
|
||||
2, 7, 3, 2, 6, 7, // bottom
|
||||
};
|
||||
|
||||
int j = 0;
|
||||
var vertices = new Vector3[triangles.Length];
|
||||
var normals = new Vector3[triangles.Length];
|
||||
for (int i = 0; i < triangles.Length / 3; i++)
|
||||
{
|
||||
var a = corners[triangles[i * 3 + 0]];
|
||||
var b = corners[triangles[i * 3 + 1]];
|
||||
var c = corners[triangles[i * 3 + 2]];
|
||||
var n = Vector3.Cross(b - a, c - a).normalized;
|
||||
normals[i * 3 + 0] = n;
|
||||
normals[i * 3 + 1] = n;
|
||||
normals[i * 3 + 2] = n;
|
||||
vertices[i * 3 + 0] = a;
|
||||
vertices[i * 3 + 1] = b;
|
||||
vertices[i * 3 + 2] = c;
|
||||
triangles[i * 3 + 0] = j++;
|
||||
triangles[i * 3 + 1] = j++;
|
||||
triangles[i * 3 + 2] = j++;
|
||||
}
|
||||
|
||||
var mesh = new Mesh();
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
mesh.triangles = triangles;
|
||||
|
||||
GetComponent<MeshFilter>().mesh = mesh;
|
||||
}
|
||||
|
||||
private void OnDeviceConnected(int i, bool connected)
|
||||
{
|
||||
if (i != (int)index)
|
||||
return;
|
||||
|
||||
GetComponent<MeshFilter>().mesh = null;
|
||||
|
||||
if (connected)
|
||||
{
|
||||
var system = OpenVR.System;
|
||||
if (system != null && system.GetTrackedDeviceClass((uint)i) == ETrackedDeviceClass.TrackingReference)
|
||||
{
|
||||
var error = ETrackedPropertyError.TrackedProp_Success;
|
||||
var result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewLeftDegrees_Float, ref error);
|
||||
if (error == ETrackedPropertyError.TrackedProp_Success)
|
||||
fovLeft = result;
|
||||
|
||||
result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewRightDegrees_Float, ref error);
|
||||
if (error == ETrackedPropertyError.TrackedProp_Success)
|
||||
fovRight = result;
|
||||
|
||||
result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewTopDegrees_Float, ref error);
|
||||
if (error == ETrackedPropertyError.TrackedProp_Success)
|
||||
fovTop = result;
|
||||
|
||||
result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewBottomDegrees_Float, ref error);
|
||||
if (error == ETrackedPropertyError.TrackedProp_Success)
|
||||
fovBottom = result;
|
||||
|
||||
result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_TrackingRangeMinimumMeters_Float, ref error);
|
||||
if (error == ETrackedPropertyError.TrackedProp_Success)
|
||||
nearZ = result;
|
||||
|
||||
result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_TrackingRangeMaximumMeters_Float, ref error);
|
||||
if (error == ETrackedPropertyError.TrackedProp_Success)
|
||||
farZ = result;
|
||||
|
||||
UpdateModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
GetComponent<MeshFilter>().mesh = null;
|
||||
SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected);
|
||||
GetComponent<MeshFilter>().mesh = null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void Update()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
UpdateModel();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Frustum.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Frustum.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2d1785fa0c551e408b6c94398847b76
|
||||
timeCreated: 1544852187
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
172
Assets/SteamVR/Scripts/SteamVR_IK.cs
Normal file
172
Assets/SteamVR/Scripts/SteamVR_IK.cs
Normal file
@ -0,0 +1,172 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Simple two bone ik solver.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_IK : MonoBehaviour
|
||||
{
|
||||
public Transform target;
|
||||
public Transform start, joint, end;
|
||||
public Transform poleVector, upVector;
|
||||
|
||||
public float blendPct = 1.0f;
|
||||
|
||||
[HideInInspector]
|
||||
public Transform startXform, jointXform, endXform;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
const float epsilon = 0.001f;
|
||||
if (blendPct < epsilon)
|
||||
return;
|
||||
|
||||
var preUp = upVector ? upVector.up : Vector3.Cross(end.position - start.position, joint.position - start.position).normalized;
|
||||
|
||||
var targetPosition = target.position;
|
||||
var targetRotation = target.rotation;
|
||||
|
||||
Vector3 forward, up, result = joint.position;
|
||||
Solve(start.position, targetPosition, poleVector.position,
|
||||
(joint.position - start.position).magnitude,
|
||||
(end.position - joint.position).magnitude,
|
||||
ref result, out forward, out up);
|
||||
|
||||
if (up == Vector3.zero)
|
||||
return;
|
||||
|
||||
var startPosition = start.position;
|
||||
var jointPosition = joint.position;
|
||||
var endPosition = end.position;
|
||||
|
||||
var startRotationLocal = start.localRotation;
|
||||
var jointRotationLocal = joint.localRotation;
|
||||
var endRotationLocal = end.localRotation;
|
||||
|
||||
var startParent = start.parent;
|
||||
var jointParent = joint.parent;
|
||||
var endParent = end.parent;
|
||||
|
||||
var startScale = start.localScale;
|
||||
var jointScale = joint.localScale;
|
||||
var endScale = end.localScale;
|
||||
|
||||
if (startXform == null)
|
||||
{
|
||||
startXform = new GameObject("startXform").transform;
|
||||
startXform.parent = transform;
|
||||
}
|
||||
|
||||
startXform.position = startPosition;
|
||||
startXform.LookAt(joint, preUp);
|
||||
start.parent = startXform;
|
||||
|
||||
if (jointXform == null)
|
||||
{
|
||||
jointXform = new GameObject("jointXform").transform;
|
||||
jointXform.parent = startXform;
|
||||
}
|
||||
|
||||
jointXform.position = jointPosition;
|
||||
jointXform.LookAt(end, preUp);
|
||||
joint.parent = jointXform;
|
||||
|
||||
if (endXform == null)
|
||||
{
|
||||
endXform = new GameObject("endXform").transform;
|
||||
endXform.parent = jointXform;
|
||||
}
|
||||
|
||||
endXform.position = endPosition;
|
||||
end.parent = endXform;
|
||||
|
||||
startXform.LookAt(result, up);
|
||||
jointXform.LookAt(targetPosition, up);
|
||||
endXform.rotation = targetRotation;
|
||||
|
||||
start.parent = startParent;
|
||||
joint.parent = jointParent;
|
||||
end.parent = endParent;
|
||||
|
||||
end.rotation = targetRotation; // optionally blend?
|
||||
|
||||
// handle blending in/out
|
||||
if (blendPct < 1.0f)
|
||||
{
|
||||
start.localRotation = Quaternion.Slerp(startRotationLocal, start.localRotation, blendPct);
|
||||
joint.localRotation = Quaternion.Slerp(jointRotationLocal, joint.localRotation, blendPct);
|
||||
end.localRotation = Quaternion.Slerp(endRotationLocal, end.localRotation, blendPct);
|
||||
}
|
||||
|
||||
// restore scale so it doesn't blow out
|
||||
start.localScale = startScale;
|
||||
joint.localScale = jointScale;
|
||||
end.localScale = endScale;
|
||||
}
|
||||
|
||||
public static bool Solve(
|
||||
Vector3 start, // shoulder / hip
|
||||
Vector3 end, // desired hand / foot position
|
||||
Vector3 poleVector, // point to aim elbow / knee toward
|
||||
float jointDist, // distance from start to elbow / knee
|
||||
float targetDist, // distance from joint to hand / ankle
|
||||
ref Vector3 result, // original and output elbow / knee position
|
||||
out Vector3 forward, out Vector3 up) // plane formed by root, joint and target
|
||||
{
|
||||
var totalDist = jointDist + targetDist;
|
||||
var start2end = end - start;
|
||||
var poleVectorDir = (poleVector - start).normalized;
|
||||
var baseDist = start2end.magnitude;
|
||||
|
||||
result = start;
|
||||
|
||||
const float epsilon = 0.001f;
|
||||
if (baseDist < epsilon)
|
||||
{
|
||||
// move jointDist toward jointTarget
|
||||
result += poleVectorDir * jointDist;
|
||||
|
||||
forward = Vector3.Cross(poleVectorDir, Vector3.up);
|
||||
up = Vector3.Cross(forward, poleVectorDir).normalized;
|
||||
}
|
||||
else
|
||||
{
|
||||
forward = start2end * (1.0f / baseDist);
|
||||
up = Vector3.Cross(forward, poleVectorDir).normalized;
|
||||
|
||||
if (baseDist + epsilon < totalDist)
|
||||
{
|
||||
// calculate the area of the triangle to determine its height
|
||||
var p = (totalDist + baseDist) * 0.5f; // half perimeter
|
||||
if (p > jointDist + epsilon && p > targetDist + epsilon)
|
||||
{
|
||||
var A = Mathf.Sqrt(p * (p - jointDist) * (p - targetDist) * (p - baseDist));
|
||||
var height = 2.0f * A / baseDist; // distance of joint from line between root and target
|
||||
|
||||
var dist = Mathf.Sqrt((jointDist * jointDist) - (height * height));
|
||||
var right = Vector3.Cross(up, forward); // no need to normalized - already orthonormal
|
||||
|
||||
result += (forward * dist) + (right * height);
|
||||
return true; // in range
|
||||
}
|
||||
else
|
||||
{
|
||||
// move jointDist toward jointTarget
|
||||
result += poleVectorDir * jointDist;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// move elboDist toward target
|
||||
result += forward * jointDist;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // edge cases
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_IK.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_IK.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea22dba3baf2ecc4d886bf2444444228
|
||||
timeCreated: 1544852187
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
502
Assets/SteamVR/Scripts/SteamVR_LoadLevel.cs
Normal file
502
Assets/SteamVR/Scripts/SteamVR_LoadLevel.cs
Normal file
@ -0,0 +1,502 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Helper for smoothing over transitions between levels.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Valve.VR;
|
||||
using System.IO;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_LoadLevel : MonoBehaviour
|
||||
{
|
||||
private static SteamVR_LoadLevel _active = null;
|
||||
public static bool loading { get { return _active != null; } }
|
||||
public static float progress
|
||||
{
|
||||
get { return (_active != null && _active.async != null) ? _active.async.progress : 0.0f; }
|
||||
}
|
||||
public static Texture progressTexture
|
||||
{
|
||||
get { return (_active != null) ? _active.renderTexture : null; }
|
||||
}
|
||||
|
||||
// Name of level to load.
|
||||
public string levelName;
|
||||
|
||||
// Name of internal process to launch (instead of levelName).
|
||||
public string internalProcessPath;
|
||||
|
||||
// The command-line args for the internal process to launch.
|
||||
public string internalProcessArgs;
|
||||
|
||||
// If true, call LoadLevelAdditiveAsync instead of LoadLevelAsync.
|
||||
public bool loadAdditive;
|
||||
|
||||
// Async load causes crashes in some apps.
|
||||
public bool loadAsync = true;
|
||||
|
||||
// Optional logo texture.
|
||||
public Texture loadingScreen;
|
||||
|
||||
// Optional progress bar textures.
|
||||
public Texture progressBarEmpty, progressBarFull;
|
||||
|
||||
// Sizes of overlays.
|
||||
public float loadingScreenWidthInMeters = 6.0f;
|
||||
public float progressBarWidthInMeters = 3.0f;
|
||||
|
||||
// If specified, the loading screen will be positioned in the player's view this far away.
|
||||
public float loadingScreenDistance = 0.0f;
|
||||
|
||||
// Optional overrides for where to display loading screen and progress bar overlays.
|
||||
// Otherwise defaults to using this object's transform.
|
||||
public Transform loadingScreenTransform, progressBarTransform;
|
||||
|
||||
// Optional skybox override textures.
|
||||
public Texture front, back, left, right, top, bottom;
|
||||
|
||||
// Colors to use when dropping to the compositor between levels if no skybox is set.
|
||||
public Color backgroundColor = Color.black;
|
||||
|
||||
// If false, the background color above gets applied as the foreground color in the compositor.
|
||||
// This does not have any effect when using a skybox instead.
|
||||
public bool showGrid = false;
|
||||
|
||||
// Time to fade from current scene to the compositor and back.
|
||||
public float fadeOutTime = 0.5f;
|
||||
public float fadeInTime = 0.5f;
|
||||
|
||||
// Additional time to wait after finished loading before we start fading the new scene back in.
|
||||
// This is to cover up any initial hitching that takes place right at the start of levels.
|
||||
// Most scenes should hopefully not require this.
|
||||
public float postLoadSettleTime = 0.0f;
|
||||
|
||||
// Time to fade loading screen in and out (also used for progress bar).
|
||||
public float loadingScreenFadeInTime = 1.0f;
|
||||
public float loadingScreenFadeOutTime = 0.25f;
|
||||
|
||||
float fadeRate = 1.0f;
|
||||
float alpha = 0.0f;
|
||||
|
||||
AsyncOperation async; // used to track level load progress
|
||||
RenderTexture renderTexture; // used to render progress bar
|
||||
|
||||
ulong loadingScreenOverlayHandle = OpenVR.k_ulOverlayHandleInvalid;
|
||||
ulong progressBarOverlayHandle = OpenVR.k_ulOverlayHandleInvalid;
|
||||
|
||||
public bool autoTriggerOnEnable = false;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (autoTriggerOnEnable)
|
||||
Trigger();
|
||||
}
|
||||
|
||||
public void Trigger()
|
||||
{
|
||||
if (!loading && !string.IsNullOrEmpty(levelName))
|
||||
StartCoroutine(LoadLevel());
|
||||
}
|
||||
|
||||
// Helper function to quickly and simply load a level from script.
|
||||
public static void Begin(string levelName,
|
||||
bool showGrid = false, float fadeOutTime = 0.5f,
|
||||
float r = 0.0f, float g = 0.0f, float b = 0.0f, float a = 1.0f)
|
||||
{
|
||||
var loader = new GameObject("loader").AddComponent<SteamVR_LoadLevel>();
|
||||
loader.levelName = levelName;
|
||||
loader.showGrid = showGrid;
|
||||
loader.fadeOutTime = fadeOutTime;
|
||||
loader.backgroundColor = new Color(r, g, b, a);
|
||||
loader.Trigger();
|
||||
}
|
||||
|
||||
// Updates progress bar.
|
||||
void OnGUI()
|
||||
{
|
||||
if (_active != this)
|
||||
return;
|
||||
|
||||
// Optionally create an overlay for our progress bar to use, separate from the loading screen.
|
||||
if (progressBarEmpty != null && progressBarFull != null)
|
||||
{
|
||||
if (progressBarOverlayHandle == OpenVR.k_ulOverlayHandleInvalid)
|
||||
progressBarOverlayHandle = GetOverlayHandle("progressBar", progressBarTransform != null ? progressBarTransform : transform, progressBarWidthInMeters);
|
||||
|
||||
if (progressBarOverlayHandle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
{
|
||||
var progress = (async != null) ? async.progress : 0.0f;
|
||||
|
||||
// Use the full bar size for everything.
|
||||
var w = progressBarFull.width;
|
||||
var h = progressBarFull.height;
|
||||
|
||||
// Create a separate render texture so we can composite the full image on top of the empty one.
|
||||
if (renderTexture == null)
|
||||
{
|
||||
renderTexture = new RenderTexture(w, h, 0);
|
||||
renderTexture.Create();
|
||||
}
|
||||
|
||||
var prevActive = RenderTexture.active;
|
||||
RenderTexture.active = renderTexture;
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
GL.Clear(false, true, Color.clear);
|
||||
|
||||
GUILayout.BeginArea(new Rect(0, 0, w, h));
|
||||
|
||||
GUI.DrawTexture(new Rect(0, 0, w, h), progressBarEmpty);
|
||||
|
||||
// Reveal the full bar texture based on progress.
|
||||
GUI.DrawTextureWithTexCoords(new Rect(0, 0, progress * w, h), progressBarFull, new Rect(0.0f, 0.0f, progress, 1.0f));
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
RenderTexture.active = prevActive;
|
||||
|
||||
// Texture needs to be set every frame after it is updated since SteamVR makes a copy internally to a shared texture.
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay != null)
|
||||
{
|
||||
var texture = new Texture_t();
|
||||
texture.handle = renderTexture.GetNativeTexturePtr();
|
||||
texture.eType = SteamVR.instance.textureType;
|
||||
texture.eColorSpace = EColorSpace.Auto;
|
||||
overlay.SetOverlayTexture(progressBarOverlayHandle, ref texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
// Draw loading screen and progress bar to 2d companion window as well.
|
||||
if (loadingScreen != null)
|
||||
{
|
||||
var screenAspect = (float)Screen.width / Screen.height;
|
||||
var textureAspect = (float)loadingScreen.width / loadingScreen.height;
|
||||
|
||||
float w, h;
|
||||
if (screenAspect < textureAspect)
|
||||
{
|
||||
// Clamp horizontally
|
||||
w = Screen.width * 0.9f;
|
||||
h = w / textureAspect;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clamp vertically
|
||||
h = Screen.height * 0.9f;
|
||||
w = h * textureAspect;
|
||||
}
|
||||
|
||||
GUILayout.BeginArea(new Rect(0, 0, Screen.width, Screen.height));
|
||||
|
||||
var x = Screen.width / 2 - w / 2;
|
||||
var y = Screen.height / 2 - h / 2;
|
||||
GUI.DrawTexture(new Rect(x, y, w, h), loadingScreen);
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
if (renderTexture != null)
|
||||
{
|
||||
var x = Screen.width / 2 - renderTexture.width / 2;
|
||||
var y = Screen.height * 0.9f - renderTexture.height;
|
||||
GUI.DrawTexture(new Rect(x, y, renderTexture.width, renderTexture.height), renderTexture);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Fade our overlays in/out over time.
|
||||
void Update()
|
||||
{
|
||||
if (_active != this)
|
||||
return;
|
||||
|
||||
alpha = Mathf.Clamp01(alpha + fadeRate * Time.deltaTime);
|
||||
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay != null)
|
||||
{
|
||||
if (loadingScreenOverlayHandle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
overlay.SetOverlayAlpha(loadingScreenOverlayHandle, alpha);
|
||||
|
||||
if (progressBarOverlayHandle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
overlay.SetOverlayAlpha(progressBarOverlayHandle, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
// Corourtine to handle all the steps across loading boundaries.
|
||||
IEnumerator LoadLevel()
|
||||
{
|
||||
// Optionally rotate loading screen transform around the camera into view.
|
||||
// We assume here that the loading screen is already facing toward the origin,
|
||||
// and that the progress bar transform (if any) is a child and will follow along.
|
||||
if (loadingScreen != null && loadingScreenDistance > 0.0f)
|
||||
{
|
||||
Transform hmd = this.transform;
|
||||
if (Camera.main != null)
|
||||
hmd = Camera.main.transform;
|
||||
|
||||
Quaternion rot = Quaternion.Euler(0.0f, hmd.eulerAngles.y, 0.0f);
|
||||
Vector3 pos = hmd.position + (rot * new Vector3(0.0f, 0.0f, loadingScreenDistance));
|
||||
|
||||
var t = loadingScreenTransform != null ? loadingScreenTransform : transform;
|
||||
t.position = pos;
|
||||
t.rotation = rot;
|
||||
}
|
||||
|
||||
_active = this;
|
||||
|
||||
SteamVR_Events.Loading.Send(true);
|
||||
|
||||
// Calculate rate for fading in loading screen and progress bar.
|
||||
if (loadingScreenFadeInTime > 0.0f)
|
||||
{
|
||||
fadeRate = 1.0f / loadingScreenFadeInTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = 1.0f;
|
||||
}
|
||||
|
||||
var overlay = OpenVR.Overlay;
|
||||
|
||||
// Optionally create our loading screen overlay.
|
||||
if (loadingScreen != null && overlay != null)
|
||||
{
|
||||
loadingScreenOverlayHandle = GetOverlayHandle("loadingScreen", loadingScreenTransform != null ? loadingScreenTransform : transform, loadingScreenWidthInMeters);
|
||||
if (loadingScreenOverlayHandle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
{
|
||||
var texture = new Texture_t();
|
||||
texture.handle = loadingScreen.GetNativeTexturePtr();
|
||||
texture.eType = SteamVR.instance.textureType;
|
||||
texture.eColorSpace = EColorSpace.Auto;
|
||||
overlay.SetOverlayTexture(loadingScreenOverlayHandle, ref texture);
|
||||
}
|
||||
}
|
||||
|
||||
bool fadedForeground = false;
|
||||
|
||||
// Fade out to compositor
|
||||
SteamVR_Events.LoadingFadeOut.Send(fadeOutTime);
|
||||
|
||||
// Optionally set a skybox to use as a backdrop in the compositor.
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
{
|
||||
if (front != null)
|
||||
{
|
||||
SteamVR_Skybox.SetOverride(front, back, left, right, top, bottom);
|
||||
|
||||
// Explicitly fade to the compositor since loading will cause us to stop rendering.
|
||||
compositor.FadeGrid(fadeOutTime, true);
|
||||
yield return new WaitForSeconds(fadeOutTime);
|
||||
}
|
||||
else if (backgroundColor != Color.clear)
|
||||
{
|
||||
// Otherwise, use the specified background color.
|
||||
if (showGrid)
|
||||
{
|
||||
// Set compositor background color immediately, and start fading to it.
|
||||
compositor.FadeToColor(0.0f, backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a, true);
|
||||
compositor.FadeGrid(fadeOutTime, true);
|
||||
yield return new WaitForSeconds(fadeOutTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fade the foreground color in (which will blend on top of the scene), and then cut to the compositor.
|
||||
compositor.FadeToColor(fadeOutTime, backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a, false);
|
||||
yield return new WaitForSeconds(fadeOutTime + 0.1f);
|
||||
compositor.FadeGrid(0.0f, true);
|
||||
fadedForeground = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we're fully faded out, we can stop submitting frames to the compositor.
|
||||
SteamVR_Render.pauseRendering = true;
|
||||
|
||||
// Continue waiting for the overlays to fully fade in before continuing.
|
||||
while (alpha < 1.0f)
|
||||
yield return null;
|
||||
|
||||
// Keep us from getting destroyed when loading the new level, otherwise this coroutine will get stopped prematurely.
|
||||
transform.parent = null;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
if (!string.IsNullOrEmpty(internalProcessPath))
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> Launching external application...");
|
||||
var applications = OpenVR.Applications;
|
||||
if (applications == null)
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> Failed to get OpenVR.Applications interface!");
|
||||
}
|
||||
else
|
||||
{
|
||||
var workingDirectory = Directory.GetCurrentDirectory();
|
||||
var fullPath = Path.Combine(workingDirectory, internalProcessPath);
|
||||
Debug.Log("<b>[SteamVR]</b> LaunchingInternalProcess");
|
||||
Debug.Log("<b>[SteamVR]</b> ExternalAppPath = " + internalProcessPath);
|
||||
Debug.Log("<b>[SteamVR]</b> FullPath = " + fullPath);
|
||||
Debug.Log("<b>[SteamVR]</b> ExternalAppArgs = " + internalProcessArgs);
|
||||
Debug.Log("<b>[SteamVR]</b> WorkingDirectory = " + workingDirectory);
|
||||
var error = applications.LaunchInternalProcess(fullPath, internalProcessArgs, workingDirectory);
|
||||
Debug.Log("<b>[SteamVR]</b> LaunchInternalProcessError: " + error);
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#elif !UNITY_METRO
|
||||
System.Diagnostics.Process.GetCurrentProcess().Kill();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var mode = loadAdditive ? UnityEngine.SceneManagement.LoadSceneMode.Additive : UnityEngine.SceneManagement.LoadSceneMode.Single;
|
||||
if (loadAsync)
|
||||
{
|
||||
Application.backgroundLoadingPriority = ThreadPriority.Low;
|
||||
async = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(levelName, mode);
|
||||
|
||||
// Performing this in a while loop instead seems to help smooth things out.
|
||||
//yield return async;
|
||||
while (!async.isDone)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.SceneManagement.SceneManager.LoadScene(levelName, mode);
|
||||
}
|
||||
}
|
||||
|
||||
yield return null;
|
||||
|
||||
System.GC.Collect();
|
||||
|
||||
yield return null;
|
||||
|
||||
Shader.WarmupAllShaders();
|
||||
|
||||
// Optionally wait a short period of time after loading everything back in, but before we start rendering again
|
||||
// in order to give everything a change to settle down to avoid any hitching at the start of the new level.
|
||||
yield return new WaitForSeconds(postLoadSettleTime);
|
||||
|
||||
SteamVR_Render.pauseRendering = false;
|
||||
|
||||
// Fade out loading screen.
|
||||
if (loadingScreenFadeOutTime > 0.0f)
|
||||
{
|
||||
fadeRate = -1.0f / loadingScreenFadeOutTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = 0.0f;
|
||||
}
|
||||
|
||||
// Fade out to compositor
|
||||
SteamVR_Events.LoadingFadeIn.Send(fadeInTime);
|
||||
|
||||
// Refresh compositor reference since loading scenes might have invalidated it.
|
||||
compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
{
|
||||
// Fade out foreground color if necessary.
|
||||
if (fadedForeground)
|
||||
{
|
||||
compositor.FadeGrid(0.0f, false);
|
||||
compositor.FadeToColor(fadeInTime, 0.0f, 0.0f, 0.0f, 0.0f, false);
|
||||
yield return new WaitForSeconds(fadeInTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fade scene back in, and reset skybox once no longer visible.
|
||||
compositor.FadeGrid(fadeInTime, false);
|
||||
yield return new WaitForSeconds(fadeInTime);
|
||||
|
||||
if (front != null)
|
||||
{
|
||||
SteamVR_Skybox.ClearOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, stick around long enough for our overlays to fully fade out.
|
||||
while (alpha > 0.0f)
|
||||
yield return null;
|
||||
|
||||
if (overlay != null)
|
||||
{
|
||||
if (progressBarOverlayHandle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
overlay.HideOverlay(progressBarOverlayHandle);
|
||||
if (loadingScreenOverlayHandle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
overlay.HideOverlay(loadingScreenOverlayHandle);
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
|
||||
_active = null;
|
||||
|
||||
SteamVR_Events.Loading.Send(false);
|
||||
}
|
||||
|
||||
// Helper to create (or reuse if possible) each of our different overlay types.
|
||||
ulong GetOverlayHandle(string overlayName, Transform transform, float widthInMeters = 1.0f)
|
||||
{
|
||||
ulong handle = OpenVR.k_ulOverlayHandleInvalid;
|
||||
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay == null)
|
||||
return handle;
|
||||
|
||||
var key = SteamVR_Overlay.key + "." + overlayName;
|
||||
|
||||
var error = overlay.FindOverlay(key, ref handle);
|
||||
if (error != EVROverlayError.None)
|
||||
error = overlay.CreateOverlay(key, overlayName, ref handle);
|
||||
if (error == EVROverlayError.None)
|
||||
{
|
||||
overlay.ShowOverlay(handle);
|
||||
overlay.SetOverlayAlpha(handle, alpha);
|
||||
overlay.SetOverlayWidthInMeters(handle, widthInMeters);
|
||||
|
||||
// D3D textures are upside-down in Unity to match OpenGL.
|
||||
if (SteamVR.instance.textureType == ETextureType.DirectX)
|
||||
{
|
||||
var textureBounds = new VRTextureBounds_t();
|
||||
textureBounds.uMin = 0;
|
||||
textureBounds.vMin = 1;
|
||||
textureBounds.uMax = 1;
|
||||
textureBounds.vMax = 0;
|
||||
overlay.SetOverlayTextureBounds(handle, ref textureBounds);
|
||||
}
|
||||
|
||||
// Convert from world space to tracking space using the top-most camera.
|
||||
var vrcam = (loadingScreenDistance == 0.0f) ? SteamVR_Render.Top() : null;
|
||||
if (vrcam != null && vrcam.origin != null)
|
||||
{
|
||||
var offset = new SteamVR_Utils.RigidTransform(vrcam.origin, transform);
|
||||
offset.pos.x /= vrcam.origin.localScale.x;
|
||||
offset.pos.y /= vrcam.origin.localScale.y;
|
||||
offset.pos.z /= vrcam.origin.localScale.z;
|
||||
|
||||
var t = offset.ToHmdMatrix34();
|
||||
overlay.SetOverlayTransformAbsolute(handle, SteamVR.settings.trackingSpace, ref t);
|
||||
}
|
||||
else
|
||||
{
|
||||
var t = new SteamVR_Utils.RigidTransform(transform).ToHmdMatrix34();
|
||||
overlay.SetOverlayTransformAbsolute(handle, SteamVR.settings.trackingSpace, ref t);
|
||||
}
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_LoadLevel.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_LoadLevel.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5a6a70209b6e6345bfe18b02314a54e
|
||||
timeCreated: 1544852188
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
321
Assets/SteamVR/Scripts/SteamVR_Menu.cs
Normal file
321
Assets/SteamVR/Scripts/SteamVR_Menu.cs
Normal file
@ -0,0 +1,321 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Example menu using OnGUI with SteamVR_Camera's overlay support
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Menu : MonoBehaviour
|
||||
{
|
||||
public Texture cursor, background, logo;
|
||||
public float logoHeight, menuOffset;
|
||||
|
||||
public Vector2 scaleLimits = new Vector2(0.1f, 5.0f);
|
||||
public float scaleRate = 0.5f;
|
||||
|
||||
SteamVR_Overlay overlay;
|
||||
Camera overlayCam;
|
||||
Vector4 uvOffset;
|
||||
float distance;
|
||||
|
||||
public RenderTexture texture { get { return overlay ? overlay.texture as RenderTexture : null; } }
|
||||
public float scale { get; private set; }
|
||||
|
||||
string scaleLimitX, scaleLimitY, scaleRateText;
|
||||
|
||||
CursorLockMode savedCursorLockState;
|
||||
bool savedCursorVisible;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
scaleLimitX = string.Format("{0:N1}", scaleLimits.x);
|
||||
scaleLimitY = string.Format("{0:N1}", scaleLimits.y);
|
||||
scaleRateText = string.Format("{0:N1}", scaleRate);
|
||||
|
||||
var overlay = SteamVR_Overlay.instance;
|
||||
if (overlay != null)
|
||||
{
|
||||
uvOffset = overlay.uvOffset;
|
||||
distance = overlay.distance;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (overlay == null)
|
||||
return;
|
||||
|
||||
var texture = overlay.texture as RenderTexture;
|
||||
|
||||
var prevActive = RenderTexture.active;
|
||||
RenderTexture.active = texture;
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
GL.Clear(false, true, Color.clear);
|
||||
|
||||
var area = new Rect(0, 0, texture.width, texture.height);
|
||||
|
||||
// Account for screen smaller than texture (since mouse position gets clamped)
|
||||
if (Screen.width < texture.width)
|
||||
{
|
||||
area.width = Screen.width;
|
||||
overlay.uvOffset.x = -(float)(texture.width - Screen.width) / (2 * texture.width);
|
||||
}
|
||||
if (Screen.height < texture.height)
|
||||
{
|
||||
area.height = Screen.height;
|
||||
overlay.uvOffset.y = (float)(texture.height - Screen.height) / (2 * texture.height);
|
||||
}
|
||||
|
||||
GUILayout.BeginArea(area);
|
||||
|
||||
if (background != null)
|
||||
{
|
||||
GUI.DrawTexture(new Rect(
|
||||
(area.width - background.width) / 2,
|
||||
(area.height - background.height) / 2,
|
||||
background.width, background.height), background);
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
if (logo != null)
|
||||
{
|
||||
GUILayout.Space(area.height / 2 - logoHeight);
|
||||
GUILayout.Box(logo);
|
||||
}
|
||||
|
||||
GUILayout.Space(menuOffset);
|
||||
|
||||
bool bHideMenu = GUILayout.Button("[Esc] - Close menu");
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(string.Format("Scale: {0:N4}", scale));
|
||||
{
|
||||
var result = GUILayout.HorizontalSlider(scale, scaleLimits.x, scaleLimits.y);
|
||||
if (result != scale)
|
||||
{
|
||||
SetScale(result);
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(string.Format("Scale limits:"));
|
||||
{
|
||||
var result = GUILayout.TextField(scaleLimitX);
|
||||
if (result != scaleLimitX)
|
||||
{
|
||||
if (float.TryParse(result, out scaleLimits.x))
|
||||
scaleLimitX = result;
|
||||
}
|
||||
}
|
||||
{
|
||||
var result = GUILayout.TextField(scaleLimitY);
|
||||
if (result != scaleLimitY)
|
||||
{
|
||||
if (float.TryParse(result, out scaleLimits.y))
|
||||
scaleLimitY = result;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(string.Format("Scale rate:"));
|
||||
{
|
||||
var result = GUILayout.TextField(scaleRateText);
|
||||
if (result != scaleRateText)
|
||||
{
|
||||
if (float.TryParse(result, out scaleRate))
|
||||
scaleRateText = result;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (SteamVR.active)
|
||||
{
|
||||
var vr = SteamVR.instance;
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
var t = SteamVR_Camera.sceneResolutionScale;
|
||||
int w = (int)(vr.sceneWidth * t);
|
||||
int h = (int)(vr.sceneHeight * t);
|
||||
int pct = (int)(100.0f * t);
|
||||
GUILayout.Label(string.Format("Scene quality: {0}x{1} ({2}%)", w, h, pct));
|
||||
var result = Mathf.RoundToInt(GUILayout.HorizontalSlider(pct, 50, 200));
|
||||
if (result != pct)
|
||||
{
|
||||
SteamVR_Camera.sceneResolutionScale = (float)result / 100.0f;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
var tracker = SteamVR_Render.Top();
|
||||
if (tracker != null)
|
||||
{
|
||||
tracker.wireframe = GUILayout.Toggle(tracker.wireframe, "Wireframe");
|
||||
|
||||
if (SteamVR.settings.trackingSpace == ETrackingUniverseOrigin.TrackingUniverseSeated)
|
||||
{
|
||||
if (GUILayout.Button("Switch to Standing"))
|
||||
SteamVR.settings.trackingSpace = ETrackingUniverseOrigin.TrackingUniverseStanding;
|
||||
|
||||
if (GUILayout.Button("Center View"))
|
||||
{
|
||||
var chaperone = OpenVR.Chaperone;
|
||||
if (chaperone != null)
|
||||
chaperone.ResetZeroPose(SteamVR.settings.trackingSpace);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Switch to Seated"))
|
||||
SteamVR.settings.trackingSpace = ETrackingUniverseOrigin.TrackingUniverseSeated;
|
||||
}
|
||||
}
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
if (GUILayout.Button("Exit"))
|
||||
Application.Quit();
|
||||
#endif
|
||||
GUILayout.Space(menuOffset);
|
||||
|
||||
var env = System.Environment.GetEnvironmentVariable("VR_OVERRIDE");
|
||||
if (env != null)
|
||||
{
|
||||
GUILayout.Label("VR_OVERRIDE=" + env);
|
||||
}
|
||||
|
||||
GUILayout.Label("Graphics device: " + SystemInfo.graphicsDeviceVersion);
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
if (cursor != null)
|
||||
{
|
||||
float x = Input.mousePosition.x, y = Screen.height - Input.mousePosition.y;
|
||||
float w = cursor.width, h = cursor.height;
|
||||
GUI.DrawTexture(new Rect(x, y, w, h), cursor);
|
||||
}
|
||||
|
||||
RenderTexture.active = prevActive;
|
||||
|
||||
if (bHideMenu)
|
||||
HideMenu();
|
||||
}
|
||||
|
||||
public void ShowMenu()
|
||||
{
|
||||
var overlay = SteamVR_Overlay.instance;
|
||||
if (overlay == null)
|
||||
return;
|
||||
|
||||
var texture = overlay.texture as RenderTexture;
|
||||
if (texture == null)
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Menu requires overlay texture to be a render texture.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
SaveCursorState();
|
||||
|
||||
Cursor.visible = true;
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
|
||||
this.overlay = overlay;
|
||||
uvOffset = overlay.uvOffset;
|
||||
distance = overlay.distance;
|
||||
|
||||
// If an existing camera is rendering into the overlay texture, we need
|
||||
// to temporarily disable it to keep it from clearing the texture on us.
|
||||
var cameras = Object.FindObjectsOfType(typeof(Camera)) as Camera[];
|
||||
foreach (var cam in cameras)
|
||||
{
|
||||
if (cam.enabled && cam.targetTexture == texture)
|
||||
{
|
||||
overlayCam = cam;
|
||||
overlayCam.enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var tracker = SteamVR_Render.Top();
|
||||
if (tracker != null)
|
||||
scale = tracker.origin.localScale.x;
|
||||
}
|
||||
|
||||
public void HideMenu()
|
||||
{
|
||||
RestoreCursorState();
|
||||
|
||||
if (overlayCam != null)
|
||||
overlayCam.enabled = true;
|
||||
|
||||
if (overlay != null)
|
||||
{
|
||||
overlay.uvOffset = uvOffset;
|
||||
overlay.distance = distance;
|
||||
overlay = null;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Joystick1Button7))
|
||||
{
|
||||
if (overlay == null)
|
||||
{
|
||||
ShowMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideMenu();
|
||||
}
|
||||
}
|
||||
else if (Input.GetKeyDown(KeyCode.Home))
|
||||
{
|
||||
SetScale(1.0f);
|
||||
}
|
||||
else if (Input.GetKey(KeyCode.PageUp))
|
||||
{
|
||||
SetScale(Mathf.Clamp(scale + scaleRate * Time.deltaTime, scaleLimits.x, scaleLimits.y));
|
||||
}
|
||||
else if (Input.GetKey(KeyCode.PageDown))
|
||||
{
|
||||
SetScale(Mathf.Clamp(scale - scaleRate * Time.deltaTime, scaleLimits.x, scaleLimits.y));
|
||||
}
|
||||
}
|
||||
|
||||
void SetScale(float scale)
|
||||
{
|
||||
this.scale = scale;
|
||||
|
||||
var tracker = SteamVR_Render.Top();
|
||||
if (tracker != null)
|
||||
tracker.origin.localScale = new Vector3(scale, scale, scale);
|
||||
}
|
||||
|
||||
void SaveCursorState()
|
||||
{
|
||||
savedCursorVisible = Cursor.visible;
|
||||
savedCursorLockState = Cursor.lockState;
|
||||
}
|
||||
|
||||
void RestoreCursorState()
|
||||
{
|
||||
Cursor.visible = savedCursorVisible;
|
||||
Cursor.lockState = savedCursorLockState;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Menu.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Menu.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7afc8c74d1f73b458705e0b946292a0
|
||||
timeCreated: 1544852188
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
172
Assets/SteamVR/Scripts/SteamVR_Overlay.cs
Normal file
172
Assets/SteamVR/Scripts/SteamVR_Overlay.cs
Normal file
@ -0,0 +1,172 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Displays 2d content on a large virtual screen.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Overlay : MonoBehaviour
|
||||
{
|
||||
public Texture texture;
|
||||
|
||||
[Tooltip("Size of overlay view.")]
|
||||
public float scale = 3.0f;
|
||||
|
||||
[Tooltip("Distance from surface.")]
|
||||
public float distance = 1.25f;
|
||||
|
||||
[Tooltip("Opacity"), Range(0.0f, 1.0f)]
|
||||
public float alpha = 1.0f;
|
||||
|
||||
public Vector4 uvOffset = new Vector4(0, 0, 1, 1);
|
||||
public Vector2 mouseScale = new Vector2(1, 1);
|
||||
|
||||
public VROverlayInputMethod inputMethod = VROverlayInputMethod.None;
|
||||
|
||||
static public SteamVR_Overlay instance { get; private set; }
|
||||
|
||||
static public string key { get { return "unity:" + Application.companyName + "." + Application.productName; } }
|
||||
|
||||
private ulong handle = OpenVR.k_ulOverlayHandleInvalid;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay != null)
|
||||
{
|
||||
var error = overlay.CreateOverlay(key, gameObject.name, ref handle);
|
||||
if (error != EVROverlayError.None)
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> " + overlay.GetOverlayErrorNameFromEnum(error));
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SteamVR_Overlay.instance = this;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (handle != OpenVR.k_ulOverlayHandleInvalid)
|
||||
{
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay != null)
|
||||
{
|
||||
overlay.DestroyOverlay(handle);
|
||||
}
|
||||
|
||||
handle = OpenVR.k_ulOverlayHandleInvalid;
|
||||
}
|
||||
|
||||
SteamVR_Overlay.instance = null;
|
||||
}
|
||||
|
||||
public void UpdateOverlay()
|
||||
{
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay == null)
|
||||
return;
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
var error = overlay.ShowOverlay(handle);
|
||||
if (error == EVROverlayError.InvalidHandle || error == EVROverlayError.UnknownOverlay)
|
||||
{
|
||||
if (overlay.FindOverlay(key, ref handle) != EVROverlayError.None)
|
||||
return;
|
||||
}
|
||||
|
||||
var tex = new Texture_t();
|
||||
tex.handle = texture.GetNativeTexturePtr();
|
||||
tex.eType = SteamVR.instance.textureType;
|
||||
tex.eColorSpace = EColorSpace.Auto;
|
||||
overlay.SetOverlayTexture(handle, ref tex);
|
||||
|
||||
overlay.SetOverlayAlpha(handle, alpha);
|
||||
overlay.SetOverlayWidthInMeters(handle, scale);
|
||||
|
||||
var textureBounds = new VRTextureBounds_t();
|
||||
textureBounds.uMin = (0 + uvOffset.x) * uvOffset.z;
|
||||
textureBounds.vMin = (1 + uvOffset.y) * uvOffset.w;
|
||||
textureBounds.uMax = (1 + uvOffset.x) * uvOffset.z;
|
||||
textureBounds.vMax = (0 + uvOffset.y) * uvOffset.w;
|
||||
overlay.SetOverlayTextureBounds(handle, ref textureBounds);
|
||||
|
||||
var vecMouseScale = new HmdVector2_t();
|
||||
vecMouseScale.v0 = mouseScale.x;
|
||||
vecMouseScale.v1 = mouseScale.y;
|
||||
overlay.SetOverlayMouseScale(handle, ref vecMouseScale);
|
||||
|
||||
var vrcam = SteamVR_Render.Top();
|
||||
if (vrcam != null && vrcam.origin != null)
|
||||
{
|
||||
var offset = new SteamVR_Utils.RigidTransform(vrcam.origin, transform);
|
||||
offset.pos.x /= vrcam.origin.localScale.x;
|
||||
offset.pos.y /= vrcam.origin.localScale.y;
|
||||
offset.pos.z /= vrcam.origin.localScale.z;
|
||||
|
||||
offset.pos.z += distance;
|
||||
|
||||
var t = offset.ToHmdMatrix34();
|
||||
overlay.SetOverlayTransformAbsolute(handle, SteamVR.settings.trackingSpace, ref t);
|
||||
}
|
||||
|
||||
overlay.SetOverlayInputMethod(handle, inputMethod);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay.HideOverlay(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public bool PollNextEvent(ref VREvent_t pEvent)
|
||||
{
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay == null)
|
||||
return false;
|
||||
|
||||
var size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(Valve.VR.VREvent_t));
|
||||
return overlay.PollNextOverlayEvent(handle, ref pEvent, size);
|
||||
}
|
||||
|
||||
public struct IntersectionResults
|
||||
{
|
||||
public Vector3 point;
|
||||
public Vector3 normal;
|
||||
public Vector2 UVs;
|
||||
public float distance;
|
||||
}
|
||||
|
||||
public bool ComputeIntersection(Vector3 source, Vector3 direction, ref IntersectionResults results)
|
||||
{
|
||||
var overlay = OpenVR.Overlay;
|
||||
if (overlay == null)
|
||||
return false;
|
||||
|
||||
var input = new VROverlayIntersectionParams_t();
|
||||
input.eOrigin = SteamVR.settings.trackingSpace;
|
||||
input.vSource.v0 = source.x;
|
||||
input.vSource.v1 = source.y;
|
||||
input.vSource.v2 = -source.z;
|
||||
input.vDirection.v0 = direction.x;
|
||||
input.vDirection.v1 = direction.y;
|
||||
input.vDirection.v2 = -direction.z;
|
||||
|
||||
var output = new VROverlayIntersectionResults_t();
|
||||
if (!overlay.ComputeOverlayIntersection(handle, ref input, ref output))
|
||||
return false;
|
||||
|
||||
results.point = new Vector3(output.vPoint.v0, output.vPoint.v1, -output.vPoint.v2);
|
||||
results.normal = new Vector3(output.vNormal.v0, output.vNormal.v1, -output.vNormal.v2);
|
||||
results.UVs = new Vector2(output.vUVs.v0, output.vUVs.v1);
|
||||
results.distance = output.fDistance;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Overlay.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Overlay.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46fe9e0b23166454c8cb73040321d78c
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
278
Assets/SteamVR/Scripts/SteamVR_PlayArea.cs
Normal file
278
Assets/SteamVR/Scripts/SteamVR_PlayArea.cs
Normal file
@ -0,0 +1,278 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Draws different sized room-scale play areas for targeting content
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using System.Collections;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[ExecuteInEditMode, RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
|
||||
public class SteamVR_PlayArea : MonoBehaviour
|
||||
{
|
||||
public float borderThickness = 0.15f;
|
||||
public float wireframeHeight = 2.0f;
|
||||
public bool drawWireframeWhenSelectedOnly = false;
|
||||
public bool drawInGame = true;
|
||||
|
||||
public enum Size
|
||||
{
|
||||
Calibrated,
|
||||
_400x300,
|
||||
_300x225,
|
||||
_200x150
|
||||
}
|
||||
|
||||
public Size size;
|
||||
public Color color = Color.cyan;
|
||||
|
||||
[HideInInspector]
|
||||
public Vector3[] vertices;
|
||||
|
||||
public static bool GetBounds(Size size, ref HmdQuad_t pRect)
|
||||
{
|
||||
if (size == Size.Calibrated)
|
||||
{
|
||||
bool temporarySession = false;
|
||||
if (Application.isEditor && Application.isPlaying == false)
|
||||
temporarySession = SteamVR.InitializeTemporarySession();
|
||||
|
||||
var chaperone = OpenVR.Chaperone;
|
||||
bool success = (chaperone != null) && chaperone.GetPlayAreaRect(ref pRect);
|
||||
if (!success)
|
||||
Debug.LogWarning("<b>[SteamVR]</b> Failed to get Calibrated Play Area bounds! Make sure you have tracking first, and that your space is calibrated.");
|
||||
|
||||
if (temporarySession)
|
||||
SteamVR.ExitTemporarySession();
|
||||
|
||||
return success;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var str = size.ToString().Substring(1);
|
||||
var arr = str.Split(new char[] { 'x' }, 2);
|
||||
|
||||
// convert to half size in meters (from cm)
|
||||
var x = float.Parse(arr[0]) / 200;
|
||||
var z = float.Parse(arr[1]) / 200;
|
||||
|
||||
pRect.vCorners0.v0 = x;
|
||||
pRect.vCorners0.v1 = 0;
|
||||
pRect.vCorners0.v2 = -z;
|
||||
|
||||
pRect.vCorners1.v0 = -x;
|
||||
pRect.vCorners1.v1 = 0;
|
||||
pRect.vCorners1.v2 = -z;
|
||||
|
||||
pRect.vCorners2.v0 = -x;
|
||||
pRect.vCorners2.v1 = 0;
|
||||
pRect.vCorners2.v2 = z;
|
||||
|
||||
pRect.vCorners3.v0 = x;
|
||||
pRect.vCorners3.v1 = 0;
|
||||
pRect.vCorners3.v2 = z;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void BuildMesh()
|
||||
{
|
||||
var rect = new HmdQuad_t();
|
||||
if (!GetBounds(size, ref rect))
|
||||
return;
|
||||
|
||||
var corners = new HmdVector3_t[] { rect.vCorners0, rect.vCorners1, rect.vCorners2, rect.vCorners3 };
|
||||
|
||||
vertices = new Vector3[corners.Length * 2];
|
||||
for (int i = 0; i < corners.Length; i++)
|
||||
{
|
||||
var c = corners[i];
|
||||
vertices[i] = new Vector3(c.v0, 0.01f, c.v2);
|
||||
}
|
||||
|
||||
if (borderThickness == 0.0f)
|
||||
{
|
||||
GetComponent<MeshFilter>().mesh = null;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < corners.Length; i++)
|
||||
{
|
||||
int next = (i + 1) % corners.Length;
|
||||
int prev = (i + corners.Length - 1) % corners.Length;
|
||||
|
||||
var nextSegment = (vertices[next] - vertices[i]).normalized;
|
||||
var prevSegment = (vertices[prev] - vertices[i]).normalized;
|
||||
|
||||
var vert = vertices[i];
|
||||
vert += Vector3.Cross(nextSegment, Vector3.up) * borderThickness;
|
||||
vert += Vector3.Cross(prevSegment, Vector3.down) * borderThickness;
|
||||
|
||||
vertices[corners.Length + i] = vert;
|
||||
}
|
||||
|
||||
var triangles = new int[]
|
||||
{
|
||||
0, 4, 1,
|
||||
1, 4, 5,
|
||||
1, 5, 2,
|
||||
2, 5, 6,
|
||||
2, 6, 3,
|
||||
3, 6, 7,
|
||||
3, 7, 0,
|
||||
0, 7, 4
|
||||
};
|
||||
|
||||
var uv = new Vector2[]
|
||||
{
|
||||
new Vector2(0.0f, 0.0f),
|
||||
new Vector2(1.0f, 0.0f),
|
||||
new Vector2(0.0f, 0.0f),
|
||||
new Vector2(1.0f, 0.0f),
|
||||
new Vector2(0.0f, 1.0f),
|
||||
new Vector2(1.0f, 1.0f),
|
||||
new Vector2(0.0f, 1.0f),
|
||||
new Vector2(1.0f, 1.0f)
|
||||
};
|
||||
|
||||
var colors = new Color[]
|
||||
{
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
new Color(color.r, color.g, color.b, 0.0f),
|
||||
new Color(color.r, color.g, color.b, 0.0f),
|
||||
new Color(color.r, color.g, color.b, 0.0f),
|
||||
new Color(color.r, color.g, color.b, 0.0f)
|
||||
};
|
||||
|
||||
var mesh = new Mesh();
|
||||
GetComponent<MeshFilter>().mesh = mesh;
|
||||
mesh.vertices = vertices;
|
||||
mesh.uv = uv;
|
||||
mesh.colors = colors;
|
||||
mesh.triangles = triangles;
|
||||
|
||||
var renderer = GetComponent<MeshRenderer>();
|
||||
renderer.material = new Material(Shader.Find("Sprites/Default"));
|
||||
renderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
|
||||
renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
renderer.receiveShadows = false;
|
||||
renderer.lightProbeUsage = LightProbeUsage.Off;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Hashtable values;
|
||||
void Update()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
|
||||
|
||||
bool rebuild = false;
|
||||
|
||||
if (values == null || (borderThickness != 0.0f && GetComponent<MeshFilter>().sharedMesh == null))
|
||||
{
|
||||
rebuild = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var f in fields)
|
||||
{
|
||||
if (!values.Contains(f) || !f.GetValue(this).Equals(values[f]))
|
||||
{
|
||||
rebuild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rebuild)
|
||||
{
|
||||
BuildMesh();
|
||||
|
||||
values = new Hashtable();
|
||||
foreach (var f in fields)
|
||||
values[f] = f.GetValue(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (!drawWireframeWhenSelectedOnly)
|
||||
DrawWireframe();
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (drawWireframeWhenSelectedOnly)
|
||||
DrawWireframe();
|
||||
}
|
||||
|
||||
public void DrawWireframe()
|
||||
{
|
||||
if (vertices == null || vertices.Length == 0)
|
||||
return;
|
||||
|
||||
var offset = transform.TransformVector(Vector3.up * wireframeHeight);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int next = (i + 1) % 4;
|
||||
|
||||
var a = transform.TransformPoint(vertices[i]);
|
||||
var b = a + offset;
|
||||
var c = transform.TransformPoint(vertices[next]);
|
||||
var d = c + offset;
|
||||
Gizmos.DrawLine(a, b);
|
||||
Gizmos.DrawLine(a, c);
|
||||
Gizmos.DrawLine(b, d);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GetComponent<MeshRenderer>().enabled = drawInGame;
|
||||
|
||||
// No need to remain enabled at runtime.
|
||||
// Anyone that wants to change properties at runtime
|
||||
// should call BuildMesh themselves.
|
||||
enabled = false;
|
||||
|
||||
// If we want the configured bounds of the user,
|
||||
// we need to wait for tracking.
|
||||
if (drawInGame && size == Size.Calibrated)
|
||||
StartCoroutine(UpdateBounds());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator UpdateBounds()
|
||||
{
|
||||
GetComponent<MeshFilter>().mesh = null; // clear existing
|
||||
|
||||
var chaperone = OpenVR.Chaperone;
|
||||
if (chaperone == null)
|
||||
yield break;
|
||||
|
||||
while (chaperone.GetCalibrationState() != ChaperoneCalibrationState.OK)
|
||||
yield return null;
|
||||
|
||||
BuildMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_PlayArea.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_PlayArea.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f0522eaef74d984591c060d05a095c8
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
469
Assets/SteamVR/Scripts/SteamVR_Render.cs
Normal file
469
Assets/SteamVR/Scripts/SteamVR_Render.cs
Normal file
@ -0,0 +1,469 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Handles rendering of all SteamVR_Cameras
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Valve.VR;
|
||||
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Render : MonoBehaviour
|
||||
{
|
||||
public SteamVR_ExternalCamera externalCamera;
|
||||
public string externalCameraConfigPath = "externalcamera.cfg";
|
||||
|
||||
public static EVREye eye { get; private set; }
|
||||
|
||||
public static SteamVR_Render instance { get { return SteamVR_Behaviour.instance.steamvr_render; } }
|
||||
|
||||
static private bool isQuitting;
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
isQuitting = true;
|
||||
SteamVR.SafeDispose();
|
||||
}
|
||||
|
||||
static public void Add(SteamVR_Camera vrcam)
|
||||
{
|
||||
if (!isQuitting)
|
||||
instance.AddInternal(vrcam);
|
||||
}
|
||||
|
||||
static public void Remove(SteamVR_Camera vrcam)
|
||||
{
|
||||
if (!isQuitting && instance != null)
|
||||
instance.RemoveInternal(vrcam);
|
||||
}
|
||||
|
||||
static public SteamVR_Camera Top()
|
||||
{
|
||||
if (!isQuitting)
|
||||
return instance.TopInternal();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private SteamVR_Camera[] cameras = new SteamVR_Camera[0];
|
||||
|
||||
void AddInternal(SteamVR_Camera vrcam)
|
||||
{
|
||||
var camera = vrcam.GetComponent<Camera>();
|
||||
var length = cameras.Length;
|
||||
var sorted = new SteamVR_Camera[length + 1];
|
||||
int insert = 0;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var c = cameras[i].GetComponent<Camera>();
|
||||
if (i == insert && c.depth > camera.depth)
|
||||
sorted[insert++] = vrcam;
|
||||
|
||||
sorted[insert++] = cameras[i];
|
||||
}
|
||||
if (insert == length)
|
||||
sorted[insert] = vrcam;
|
||||
|
||||
cameras = sorted;
|
||||
}
|
||||
|
||||
void RemoveInternal(SteamVR_Camera vrcam)
|
||||
{
|
||||
var length = cameras.Length;
|
||||
int count = 0;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var c = cameras[i];
|
||||
if (c == vrcam)
|
||||
++count;
|
||||
}
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
var sorted = new SteamVR_Camera[length - count];
|
||||
int insert = 0;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var c = cameras[i];
|
||||
if (c != vrcam)
|
||||
sorted[insert++] = c;
|
||||
}
|
||||
|
||||
cameras = sorted;
|
||||
}
|
||||
|
||||
SteamVR_Camera TopInternal()
|
||||
{
|
||||
if (cameras.Length > 0)
|
||||
return cameras[cameras.Length - 1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TrackedDevicePose_t[] poses = new TrackedDevicePose_t[OpenVR.k_unMaxTrackedDeviceCount];
|
||||
public TrackedDevicePose_t[] gamePoses = new TrackedDevicePose_t[0];
|
||||
|
||||
static private bool _pauseRendering;
|
||||
static public bool pauseRendering
|
||||
{
|
||||
get { return _pauseRendering; }
|
||||
set
|
||||
{
|
||||
_pauseRendering = value;
|
||||
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
compositor.SuspendRendering(value);
|
||||
}
|
||||
}
|
||||
|
||||
private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
|
||||
|
||||
private IEnumerator RenderLoop()
|
||||
{
|
||||
while (Application.isPlaying)
|
||||
{
|
||||
yield return waitForEndOfFrame;
|
||||
|
||||
if (pauseRendering)
|
||||
continue;
|
||||
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
{
|
||||
if (!compositor.CanRenderScene())
|
||||
continue;
|
||||
|
||||
compositor.SetTrackingSpace(SteamVR.settings.trackingSpace);
|
||||
}
|
||||
|
||||
var overlay = SteamVR_Overlay.instance;
|
||||
if (overlay != null)
|
||||
overlay.UpdateOverlay();
|
||||
|
||||
if (CheckExternalCamera())
|
||||
RenderExternalCamera();
|
||||
}
|
||||
}
|
||||
|
||||
private bool? doesPathExist = null;
|
||||
private bool CheckExternalCamera()
|
||||
{
|
||||
if (doesPathExist == false)
|
||||
return false;
|
||||
else if (doesPathExist == null)
|
||||
doesPathExist = System.IO.File.Exists(externalCameraConfigPath);
|
||||
|
||||
if (externalCamera == null && doesPathExist == true)
|
||||
{
|
||||
GameObject prefab = Resources.Load<GameObject>("SteamVR_ExternalCamera");
|
||||
if (prefab == null)
|
||||
{
|
||||
doesPathExist = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SteamVR_Settings.instance.legacyMixedRealityCamera)
|
||||
{
|
||||
if (SteamVR_ExternalCamera_LegacyManager.hasCamera == false)
|
||||
return false;
|
||||
|
||||
GameObject instance = Instantiate(prefab);
|
||||
instance.gameObject.name = "External Camera";
|
||||
|
||||
externalCamera = instance.transform.GetChild(0).GetComponent<SteamVR_ExternalCamera>();
|
||||
externalCamera.configPath = externalCameraConfigPath;
|
||||
externalCamera.ReadConfig();
|
||||
externalCamera.SetupDeviceIndex(SteamVR_ExternalCamera_LegacyManager.cameraIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
SteamVR_Action_Pose cameraPose = SteamVR_Settings.instance.mixedRealityCameraPose;
|
||||
SteamVR_Input_Sources cameraSource = SteamVR_Settings.instance.mixedRealityCameraInputSource;
|
||||
|
||||
if (cameraPose != null && SteamVR_Settings.instance.mixedRealityActionSetAutoEnable)
|
||||
{
|
||||
if (cameraPose.actionSet != null && cameraPose.actionSet.IsActive(cameraSource) == false)
|
||||
cameraPose.actionSet.Activate(cameraSource);
|
||||
}
|
||||
|
||||
if (cameraPose == null)
|
||||
{
|
||||
doesPathExist = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cameraPose != null && cameraPose[cameraSource].active && cameraPose[cameraSource].deviceIsConnected)
|
||||
{
|
||||
GameObject instance = Instantiate(prefab);
|
||||
instance.gameObject.name = "External Camera";
|
||||
|
||||
externalCamera = instance.transform.GetChild(0).GetComponent<SteamVR_ExternalCamera>();
|
||||
externalCamera.configPath = externalCameraConfigPath;
|
||||
externalCamera.ReadConfig();
|
||||
externalCamera.SetupPose(cameraPose, cameraSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (externalCamera != null);
|
||||
}
|
||||
|
||||
void RenderExternalCamera()
|
||||
{
|
||||
if (externalCamera == null)
|
||||
return;
|
||||
|
||||
if (!externalCamera.gameObject.activeInHierarchy)
|
||||
return;
|
||||
|
||||
var frameSkip = (int)Mathf.Max(externalCamera.config.frameSkip, 0.0f);
|
||||
if (Time.frameCount % (frameSkip + 1) != 0)
|
||||
return;
|
||||
|
||||
// Keep external camera relative to the most relevant vr camera.
|
||||
externalCamera.AttachToCamera(TopInternal());
|
||||
|
||||
externalCamera.RenderNear();
|
||||
externalCamera.RenderFar();
|
||||
}
|
||||
|
||||
float sceneResolutionScale = 1.0f, timeScale = 1.0f;
|
||||
|
||||
private void OnInputFocus(bool hasFocus)
|
||||
{
|
||||
if (SteamVR.active == false)
|
||||
return;
|
||||
|
||||
if (hasFocus)
|
||||
{
|
||||
if (SteamVR.settings.pauseGameWhenDashboardVisible)
|
||||
{
|
||||
Time.timeScale = timeScale;
|
||||
}
|
||||
|
||||
SteamVR_Camera.sceneResolutionScale = sceneResolutionScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SteamVR.settings.pauseGameWhenDashboardVisible)
|
||||
{
|
||||
timeScale = Time.timeScale;
|
||||
Time.timeScale = 0.0f;
|
||||
}
|
||||
|
||||
sceneResolutionScale = SteamVR_Camera.sceneResolutionScale;
|
||||
SteamVR_Camera.sceneResolutionScale = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetScreenshotFilename(uint screenshotHandle, EVRScreenshotPropertyFilenames screenshotPropertyFilename)
|
||||
{
|
||||
var error = EVRScreenshotError.None;
|
||||
var capacity = OpenVR.Screenshots.GetScreenshotPropertyFilename(screenshotHandle, screenshotPropertyFilename, null, 0, ref error);
|
||||
if (error != EVRScreenshotError.None && error != EVRScreenshotError.BufferTooSmall)
|
||||
return null;
|
||||
if (capacity > 1)
|
||||
{
|
||||
var result = new System.Text.StringBuilder((int)capacity);
|
||||
OpenVR.Screenshots.GetScreenshotPropertyFilename(screenshotHandle, screenshotPropertyFilename, result, capacity, ref error);
|
||||
if (error != EVRScreenshotError.None)
|
||||
return null;
|
||||
return result.ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnRequestScreenshot(VREvent_t vrEvent)
|
||||
{
|
||||
var screenshotHandle = vrEvent.data.screenshot.handle;
|
||||
var screenshotType = (EVRScreenshotType)vrEvent.data.screenshot.type;
|
||||
|
||||
if (screenshotType == EVRScreenshotType.StereoPanorama)
|
||||
{
|
||||
string previewFilename = GetScreenshotFilename(screenshotHandle, EVRScreenshotPropertyFilenames.Preview);
|
||||
string VRFilename = GetScreenshotFilename(screenshotHandle, EVRScreenshotPropertyFilenames.VR);
|
||||
|
||||
if (previewFilename == null || VRFilename == null)
|
||||
return;
|
||||
|
||||
// Do the stereo panorama screenshot
|
||||
// Figure out where the view is
|
||||
GameObject screenshotPosition = new GameObject("screenshotPosition");
|
||||
screenshotPosition.transform.position = SteamVR_Render.Top().transform.position;
|
||||
screenshotPosition.transform.rotation = SteamVR_Render.Top().transform.rotation;
|
||||
screenshotPosition.transform.localScale = SteamVR_Render.Top().transform.lossyScale;
|
||||
SteamVR_Utils.TakeStereoScreenshot(screenshotHandle, screenshotPosition, 32, 0.064f, ref previewFilename, ref VRFilename);
|
||||
|
||||
// and submit it
|
||||
OpenVR.Screenshots.SubmitScreenshot(screenshotHandle, screenshotType, previewFilename, VRFilename);
|
||||
}
|
||||
}
|
||||
|
||||
private EVRScreenshotType[] screenshotTypes = new EVRScreenshotType[] { EVRScreenshotType.StereoPanorama };
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
StartCoroutine(RenderLoop());
|
||||
SteamVR_Events.InputFocus.Listen(OnInputFocus);
|
||||
SteamVR_Events.System(EVREventType.VREvent_RequestScreenshot).Listen(OnRequestScreenshot);
|
||||
|
||||
if (SteamVR_Settings.instance.legacyMixedRealityCamera)
|
||||
SteamVR_ExternalCamera_LegacyManager.SubscribeToNewPoses();
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
Application.onBeforeRender += OnBeforeRender;
|
||||
#else
|
||||
Camera.onPreCull += OnCameraPreCull;
|
||||
#endif
|
||||
|
||||
if (SteamVR.initializedState == SteamVR.InitializedStates.InitializeSuccess)
|
||||
OpenVR.Screenshots.HookScreenshot(screenshotTypes);
|
||||
else
|
||||
SteamVR_Events.Initialized.AddListener(OnSteamVRInitialized);
|
||||
}
|
||||
|
||||
private void OnSteamVRInitialized(bool success)
|
||||
{
|
||||
if (success)
|
||||
OpenVR.Screenshots.HookScreenshot(screenshotTypes);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
SteamVR_Events.InputFocus.Remove(OnInputFocus);
|
||||
SteamVR_Events.System(EVREventType.VREvent_RequestScreenshot).Remove(OnRequestScreenshot);
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
Application.onBeforeRender -= OnBeforeRender;
|
||||
#else
|
||||
Camera.onPreCull -= OnCameraPreCull;
|
||||
#endif
|
||||
|
||||
if (SteamVR.initializedState != SteamVR.InitializedStates.InitializeSuccess)
|
||||
SteamVR_Events.Initialized.RemoveListener(OnSteamVRInitialized);
|
||||
}
|
||||
|
||||
public void UpdatePoses()
|
||||
{
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
{
|
||||
compositor.GetLastPoses(poses, gamePoses);
|
||||
SteamVR_Events.NewPoses.Send(poses);
|
||||
SteamVR_Events.NewPosesApplied.Send();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
void OnBeforeRender()
|
||||
{
|
||||
if (SteamVR.active == false)
|
||||
return;
|
||||
|
||||
if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnPreCull))
|
||||
{
|
||||
UpdatePoses();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void OnCameraPreCull(Camera cam)
|
||||
{
|
||||
if (SteamVR.active == false)
|
||||
return;
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
if (cam.cameraType != CameraType.VR)
|
||||
return;
|
||||
#else
|
||||
//custom code
|
||||
if (!cam.stereoEnabled) //if not main camera (stereoEnabled isn't perfect, but it is the fast/easiest way to check this in Unity 5.4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// Only update poses on the first camera per frame.
|
||||
if (Time.frameCount != lastFrameCount)
|
||||
{
|
||||
lastFrameCount = Time.frameCount;
|
||||
|
||||
if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnPreCull))
|
||||
{
|
||||
UpdatePoses();
|
||||
}
|
||||
}
|
||||
}
|
||||
static int lastFrameCount = -1;
|
||||
#endif
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (SteamVR.active == false)
|
||||
return;
|
||||
|
||||
// Dispatch any OpenVR events.
|
||||
var system = OpenVR.System;
|
||||
if (system == null)
|
||||
return;
|
||||
|
||||
UpdatePoses();
|
||||
|
||||
var vrEvent = new VREvent_t();
|
||||
var size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(VREvent_t));
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (!system.PollNextEvent(ref vrEvent, size))
|
||||
break;
|
||||
|
||||
switch ((EVREventType)vrEvent.eventType)
|
||||
{
|
||||
case EVREventType.VREvent_InputFocusCaptured: // another app has taken focus (likely dashboard)
|
||||
if (vrEvent.data.process.oldPid == 0)
|
||||
{
|
||||
SteamVR_Events.InputFocus.Send(false);
|
||||
}
|
||||
break;
|
||||
case EVREventType.VREvent_InputFocusReleased: // that app has released input focus
|
||||
if (vrEvent.data.process.pid == 0)
|
||||
{
|
||||
SteamVR_Events.InputFocus.Send(true);
|
||||
}
|
||||
break;
|
||||
case EVREventType.VREvent_ShowRenderModels:
|
||||
SteamVR_Events.HideRenderModels.Send(false);
|
||||
break;
|
||||
case EVREventType.VREvent_HideRenderModels:
|
||||
SteamVR_Events.HideRenderModels.Send(true);
|
||||
break;
|
||||
default:
|
||||
SteamVR_Events.System((EVREventType)vrEvent.eventType).Send(vrEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure various settings to minimize latency.
|
||||
Application.targetFrameRate = -1;
|
||||
Application.runInBackground = true; // don't require companion window focus
|
||||
QualitySettings.maxQueuedFrames = -1;
|
||||
QualitySettings.vSyncCount = 0; // this applies to the companion window
|
||||
|
||||
if (SteamVR.settings.lockPhysicsUpdateRateToRenderFrequency && Time.timeScale > 0.0f)
|
||||
{
|
||||
var vr = SteamVR.instance;
|
||||
if (vr != null && Application.isPlaying)
|
||||
{
|
||||
//var timing = new Compositor_FrameTiming();
|
||||
//timing.m_nSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(Compositor_FrameTiming));
|
||||
//vr.compositor.GetFrameTiming(ref timing, 0);
|
||||
|
||||
Time.fixedDeltaTime = Time.timeScale / vr.hmd_DisplayFrequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Render.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Render.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e979227f3384fac4b8ca0b3550bf005c
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -31800
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
875
Assets/SteamVR/Scripts/SteamVR_RenderModel.cs
Normal file
875
Assets/SteamVR/Scripts/SteamVR_RenderModel.cs
Normal file
@ -0,0 +1,875 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Render model of associated tracked object
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class SteamVR_RenderModel : MonoBehaviour
|
||||
{
|
||||
public SteamVR_TrackedObject.EIndex index = SteamVR_TrackedObject.EIndex.None;
|
||||
protected SteamVR_Input_Sources inputSource;
|
||||
|
||||
public const string modelOverrideWarning = "Model override is really only meant to be used in " +
|
||||
"the scene view for lining things up; using it at runtime is discouraged. Use tracked device " +
|
||||
"index instead to ensure the correct model is displayed for all users.";
|
||||
|
||||
[Tooltip(modelOverrideWarning)]
|
||||
public string modelOverride;
|
||||
|
||||
[Tooltip("Shader to apply to model.")]
|
||||
public Shader shader;
|
||||
|
||||
[Tooltip("Enable to print out when render models are loaded.")]
|
||||
public bool verbose = false;
|
||||
|
||||
[Tooltip("If available, break down into separate components instead of loading as a single mesh.")]
|
||||
public bool createComponents = true;
|
||||
|
||||
[Tooltip("Update transforms of components at runtime to reflect user action.")]
|
||||
public bool updateDynamically = true;
|
||||
|
||||
// Additional controller settings for showing scrollwheel, etc.
|
||||
public RenderModel_ControllerMode_State_t controllerModeState;
|
||||
|
||||
// Name of the sub-object which represents the "local" coordinate space for each component.
|
||||
public const string k_localTransformName = "attach";
|
||||
|
||||
// Cached name of this render model for updating component transforms at runtime.
|
||||
public string renderModelName { get; private set; }
|
||||
|
||||
public bool initializedAttachPoints { get; set; }
|
||||
|
||||
private Dictionary<string, Transform> componentAttachPoints = new Dictionary<string, Transform>();
|
||||
|
||||
private List<MeshRenderer> meshRenderers = new List<MeshRenderer>();
|
||||
|
||||
// If someone knows how to keep these from getting cleaned up every time
|
||||
// you exit play mode, let me know. I've tried marking the RenderModel
|
||||
// class below as [System.Serializable] and switching to normal public
|
||||
// variables for mesh and material to get them to serialize properly,
|
||||
// as well as tried marking the mesh and material objects as
|
||||
// DontUnloadUnusedAsset, but Unity was still unloading them.
|
||||
// The hashtable is preserving its entries, but the mesh and material
|
||||
// variables are going null.
|
||||
|
||||
public class RenderModel
|
||||
{
|
||||
public RenderModel(Mesh mesh, Material material)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
this.material = material;
|
||||
}
|
||||
public Mesh mesh { get; private set; }
|
||||
public Material material { get; private set; }
|
||||
}
|
||||
|
||||
public static Hashtable models = new Hashtable();
|
||||
public static Hashtable materials = new Hashtable();
|
||||
|
||||
// Helper class to load render models interface on demand and clean up when done.
|
||||
public sealed class RenderModelInterfaceHolder : System.IDisposable
|
||||
{
|
||||
private bool needsShutdown, failedLoadInterface;
|
||||
private CVRRenderModels _instance;
|
||||
public CVRRenderModels instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null && !failedLoadInterface)
|
||||
{
|
||||
if (Application.isEditor && Application.isPlaying == false)
|
||||
needsShutdown = SteamVR.InitializeTemporarySession();
|
||||
|
||||
_instance = OpenVR.RenderModels;
|
||||
if (_instance == null)
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Failed to load IVRRenderModels interface version " + OpenVR.IVRRenderModels_Version);
|
||||
failedLoadInterface = true;
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
if (needsShutdown)
|
||||
SteamVR.ExitTemporarySession();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModelSkinSettingsHaveChanged(VREvent_t vrEvent)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(renderModelName))
|
||||
{
|
||||
renderModelName = "";
|
||||
UpdateModel();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMeshRendererState(bool state)
|
||||
{
|
||||
for (int rendererIndex = 0; rendererIndex < meshRenderers.Count; rendererIndex++)
|
||||
{
|
||||
MeshRenderer renderer = meshRenderers[rendererIndex];
|
||||
|
||||
if (renderer != null)
|
||||
renderer.enabled = state;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHideRenderModels(bool hidden)
|
||||
{
|
||||
SetMeshRendererState(!hidden);
|
||||
}
|
||||
|
||||
private void OnDeviceConnected(int i, bool connected)
|
||||
{
|
||||
if (i != (int)index)
|
||||
return;
|
||||
|
||||
if (connected)
|
||||
{
|
||||
UpdateModel();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateModel()
|
||||
{
|
||||
var system = OpenVR.System;
|
||||
if (system == null || index == SteamVR_TrackedObject.EIndex.None)
|
||||
return;
|
||||
|
||||
var error = ETrackedPropertyError.TrackedProp_Success;
|
||||
var capacity = system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, null, 0, ref error);
|
||||
if (capacity <= 1)
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Failed to get render model name for tracked object " + index);
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = new System.Text.StringBuilder((int)capacity);
|
||||
system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, buffer, capacity, ref error);
|
||||
|
||||
var s = buffer.ToString();
|
||||
if (renderModelName != s)
|
||||
{
|
||||
StartCoroutine(SetModelAsync(s));
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator SetModelAsync(string newRenderModelName)
|
||||
{
|
||||
meshRenderers.Clear();
|
||||
|
||||
if (string.IsNullOrEmpty(newRenderModelName))
|
||||
yield break;
|
||||
|
||||
// Preload all render models before asking for the data to create meshes.
|
||||
using (RenderModelInterfaceHolder holder = new RenderModelInterfaceHolder())
|
||||
{
|
||||
CVRRenderModels renderModels = holder.instance;
|
||||
if (renderModels == null)
|
||||
yield break;
|
||||
|
||||
// Gather names of render models to preload.
|
||||
string[] renderModelNames;
|
||||
|
||||
uint count = renderModels.GetComponentCount(newRenderModelName);
|
||||
if (count > 0)
|
||||
{
|
||||
renderModelNames = new string[count];
|
||||
|
||||
for (int componentIndex = 0; componentIndex < count; componentIndex++)
|
||||
{
|
||||
uint capacity = renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, null, 0);
|
||||
if (capacity == 0)
|
||||
continue;
|
||||
|
||||
var componentNameStringBuilder = new System.Text.StringBuilder((int)capacity);
|
||||
if (renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, componentNameStringBuilder, capacity) == 0)
|
||||
continue;
|
||||
|
||||
string componentName = componentNameStringBuilder.ToString();
|
||||
|
||||
capacity = renderModels.GetComponentRenderModelName(newRenderModelName, componentName, null, 0);
|
||||
if (capacity == 0)
|
||||
continue;
|
||||
|
||||
var nameStringBuilder = new System.Text.StringBuilder((int)capacity);
|
||||
if (renderModels.GetComponentRenderModelName(newRenderModelName, componentName, nameStringBuilder, capacity) == 0)
|
||||
continue;
|
||||
|
||||
var s = nameStringBuilder.ToString();
|
||||
|
||||
// Only need to preload if not already cached.
|
||||
RenderModel model = models[s] as RenderModel;
|
||||
if (model == null || model.mesh == null)
|
||||
{
|
||||
renderModelNames[componentIndex] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only need to preload if not already cached.
|
||||
RenderModel model = models[newRenderModelName] as RenderModel;
|
||||
if (model == null || model.mesh == null)
|
||||
{
|
||||
renderModelNames = new string[] { newRenderModelName };
|
||||
}
|
||||
else
|
||||
{
|
||||
renderModelNames = new string[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Keep trying every 100ms until all components finish loading.
|
||||
while (true)
|
||||
{
|
||||
var loading = false;
|
||||
for (int renderModelNameIndex = 0; renderModelNameIndex < renderModelNames.Length; renderModelNameIndex++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(renderModelNames[renderModelNameIndex]))
|
||||
continue;
|
||||
|
||||
var pRenderModel = System.IntPtr.Zero;
|
||||
|
||||
var error = renderModels.LoadRenderModel_Async(renderModelNames[renderModelNameIndex], ref pRenderModel);
|
||||
//Debug.Log("<b>[SteamVR]</b> renderModels.LoadRenderModel_Async(" + renderModelNames[renderModelNameIndex] + ": " + error.ToString());
|
||||
|
||||
if (error == EVRRenderModelError.Loading)
|
||||
{
|
||||
loading = true;
|
||||
}
|
||||
else if (error == EVRRenderModelError.None)
|
||||
{
|
||||
// Preload textures as well.
|
||||
var renderModel = MarshalRenderModel(pRenderModel);
|
||||
|
||||
// Check the cache first.
|
||||
var material = materials[renderModel.diffuseTextureId] as Material;
|
||||
if (material == null || material.mainTexture == null)
|
||||
{
|
||||
var pDiffuseTexture = System.IntPtr.Zero;
|
||||
|
||||
error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
|
||||
//Debug.Log("<b>[SteamVR]</b> renderModels.LoadRenderModel_Async(" + renderModelNames[renderModelNameIndex] + ": " + error.ToString());
|
||||
|
||||
if (error == EVRRenderModelError.Loading)
|
||||
{
|
||||
loading = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loading)
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool success = SetModel(newRenderModelName);
|
||||
this.renderModelName = newRenderModelName;
|
||||
SteamVR_Events.RenderModelLoaded.Send(this, success);
|
||||
}
|
||||
|
||||
private bool SetModel(string renderModelName)
|
||||
{
|
||||
StripMesh(gameObject);
|
||||
|
||||
using (var holder = new RenderModelInterfaceHolder())
|
||||
{
|
||||
if (createComponents)
|
||||
{
|
||||
componentAttachPoints.Clear();
|
||||
|
||||
if (LoadComponents(holder, renderModelName))
|
||||
{
|
||||
UpdateComponents(holder.instance);
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.Log("<b>[SteamVR]</b> [" + gameObject.name + "] Render model does not support components, falling back to single mesh.");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(renderModelName))
|
||||
{
|
||||
var model = models[renderModelName] as RenderModel;
|
||||
if (model == null || model.mesh == null)
|
||||
{
|
||||
var renderModels = holder.instance;
|
||||
if (renderModels == null)
|
||||
return false;
|
||||
|
||||
if (verbose)
|
||||
Debug.Log("<b>[SteamVR]</b> Loading render model " + renderModelName);
|
||||
|
||||
model = LoadRenderModel(renderModels, renderModelName, renderModelName);
|
||||
if (model == null)
|
||||
return false;
|
||||
|
||||
models[renderModelName] = model;
|
||||
}
|
||||
|
||||
gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
|
||||
MeshRenderer newRenderer = gameObject.AddComponent<MeshRenderer>();
|
||||
newRenderer.sharedMaterial = model.material;
|
||||
meshRenderers.Add(newRenderer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderModel LoadRenderModel(CVRRenderModels renderModels, string renderModelName, string baseName)
|
||||
{
|
||||
var pRenderModel = System.IntPtr.Zero;
|
||||
|
||||
EVRRenderModelError error;
|
||||
while (true)
|
||||
{
|
||||
error = renderModels.LoadRenderModel_Async(renderModelName, ref pRenderModel);
|
||||
if (error != EVRRenderModelError.Loading)
|
||||
break;
|
||||
|
||||
Sleep();
|
||||
}
|
||||
|
||||
if (error != EVRRenderModelError.None)
|
||||
{
|
||||
Debug.LogError(string.Format("<b>[SteamVR]</b> Failed to load render model {0} - {1}", renderModelName, error.ToString()));
|
||||
return null;
|
||||
}
|
||||
|
||||
var renderModel = MarshalRenderModel(pRenderModel);
|
||||
|
||||
var vertices = new Vector3[renderModel.unVertexCount];
|
||||
var normals = new Vector3[renderModel.unVertexCount];
|
||||
var uv = new Vector2[renderModel.unVertexCount];
|
||||
|
||||
var type = typeof(RenderModel_Vertex_t);
|
||||
for (int iVert = 0; iVert < renderModel.unVertexCount; iVert++)
|
||||
{
|
||||
var ptr = new System.IntPtr(renderModel.rVertexData.ToInt64() + iVert * Marshal.SizeOf(type));
|
||||
var vert = (RenderModel_Vertex_t)Marshal.PtrToStructure(ptr, type);
|
||||
|
||||
vertices[iVert] = new Vector3(vert.vPosition.v0, vert.vPosition.v1, -vert.vPosition.v2);
|
||||
normals[iVert] = new Vector3(vert.vNormal.v0, vert.vNormal.v1, -vert.vNormal.v2);
|
||||
uv[iVert] = new Vector2(vert.rfTextureCoord0, vert.rfTextureCoord1);
|
||||
}
|
||||
|
||||
int indexCount = (int)renderModel.unTriangleCount * 3;
|
||||
var indices = new short[indexCount];
|
||||
Marshal.Copy(renderModel.rIndexData, indices, 0, indices.Length);
|
||||
|
||||
var triangles = new int[indexCount];
|
||||
for (int iTri = 0; iTri < renderModel.unTriangleCount; iTri++)
|
||||
{
|
||||
triangles[iTri * 3 + 0] = (int)indices[iTri * 3 + 2];
|
||||
triangles[iTri * 3 + 1] = (int)indices[iTri * 3 + 1];
|
||||
triangles[iTri * 3 + 2] = (int)indices[iTri * 3 + 0];
|
||||
}
|
||||
|
||||
var mesh = new Mesh();
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
mesh.uv = uv;
|
||||
mesh.triangles = triangles;
|
||||
|
||||
#if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
mesh.Optimize();
|
||||
#endif
|
||||
//mesh.hideFlags = HideFlags.DontUnloadUnusedAsset;
|
||||
|
||||
// Check cache before loading texture.
|
||||
var material = materials[renderModel.diffuseTextureId] as Material;
|
||||
if (material == null || material.mainTexture == null)
|
||||
{
|
||||
var pDiffuseTexture = System.IntPtr.Zero;
|
||||
|
||||
while (true)
|
||||
{
|
||||
error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
|
||||
if (error != EVRRenderModelError.Loading)
|
||||
break;
|
||||
|
||||
Sleep();
|
||||
}
|
||||
|
||||
if (error == EVRRenderModelError.None)
|
||||
{
|
||||
var diffuseTexture = MarshalRenderModel_TextureMap(pDiffuseTexture);
|
||||
var texture = new Texture2D(diffuseTexture.unWidth, diffuseTexture.unHeight, TextureFormat.RGBA32, false);
|
||||
if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11)
|
||||
{
|
||||
texture.Apply();
|
||||
System.IntPtr texturePointer = texture.GetNativeTexturePtr();
|
||||
while (true)
|
||||
{
|
||||
error = renderModels.LoadIntoTextureD3D11_Async(renderModel.diffuseTextureId, texturePointer);
|
||||
if (error != EVRRenderModelError.Loading)
|
||||
break;
|
||||
|
||||
Sleep();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var textureMapData = new byte[diffuseTexture.unWidth * diffuseTexture.unHeight * 4]; // RGBA
|
||||
Marshal.Copy(diffuseTexture.rubTextureMapData, textureMapData, 0, textureMapData.Length);
|
||||
|
||||
var colors = new Color32[diffuseTexture.unWidth * diffuseTexture.unHeight];
|
||||
int iColor = 0;
|
||||
for (int iHeight = 0; iHeight < diffuseTexture.unHeight; iHeight++)
|
||||
{
|
||||
for (int iWidth = 0; iWidth < diffuseTexture.unWidth; iWidth++)
|
||||
{
|
||||
var r = textureMapData[iColor++];
|
||||
var g = textureMapData[iColor++];
|
||||
var b = textureMapData[iColor++];
|
||||
var a = textureMapData[iColor++];
|
||||
colors[iHeight * diffuseTexture.unWidth + iWidth] = new Color32(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
texture.SetPixels32(colors);
|
||||
texture.Apply();
|
||||
}
|
||||
|
||||
#if UNITY_URP
|
||||
material = new Material(shader != null ? shader : Shader.Find("Universal Render Pipeline/Lit"));
|
||||
#else
|
||||
material = new Material(shader != null ? shader : Shader.Find("Standard"));
|
||||
#endif
|
||||
|
||||
material.mainTexture = texture;
|
||||
//material.hideFlags = HideFlags.DontUnloadUnusedAsset;
|
||||
|
||||
materials[renderModel.diffuseTextureId] = material;
|
||||
|
||||
renderModels.FreeTexture(pDiffuseTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> Failed to load render model texture for render model " + renderModelName + ". Error: " + error.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// Delay freeing when we can since we'll often get multiple requests for the same model right
|
||||
// after another (e.g. two controllers or two basestations).
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
renderModels.FreeRenderModel(pRenderModel);
|
||||
else
|
||||
#endif
|
||||
StartCoroutine(FreeRenderModel(pRenderModel));
|
||||
|
||||
return new RenderModel(mesh, material);
|
||||
}
|
||||
|
||||
IEnumerator FreeRenderModel(System.IntPtr pRenderModel)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
|
||||
using (var holder = new RenderModelInterfaceHolder())
|
||||
{
|
||||
var renderModels = holder.instance;
|
||||
renderModels.FreeRenderModel(pRenderModel);
|
||||
}
|
||||
}
|
||||
|
||||
public Transform FindTransformByName(string componentName, Transform inTransform = null)
|
||||
{
|
||||
if (inTransform == null)
|
||||
inTransform = this.transform;
|
||||
|
||||
for (int childIndex = 0; childIndex < inTransform.childCount; childIndex++)
|
||||
{
|
||||
Transform child = inTransform.GetChild(childIndex);
|
||||
if (child.name == componentName)
|
||||
return child;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Transform GetComponentTransform(string componentName)
|
||||
{
|
||||
if (componentName == null)
|
||||
return this.transform;
|
||||
|
||||
if (componentAttachPoints.ContainsKey(componentName))
|
||||
return componentAttachPoints[componentName];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void StripMesh(GameObject go)
|
||||
{
|
||||
var meshRenderer = go.GetComponent<MeshRenderer>();
|
||||
if (meshRenderer != null)
|
||||
DestroyImmediate(meshRenderer);
|
||||
|
||||
var meshFilter = go.GetComponent<MeshFilter>();
|
||||
if (meshFilter != null)
|
||||
DestroyImmediate(meshFilter);
|
||||
}
|
||||
|
||||
private bool LoadComponents(RenderModelInterfaceHolder holder, string renderModelName)
|
||||
{
|
||||
// Disable existing components (we will re-enable them if referenced by this new model).
|
||||
// Also strip mesh filter and renderer since these will get re-added if the new component needs them.
|
||||
var t = transform;
|
||||
for (int childIndex = 0; childIndex < t.childCount; childIndex++)
|
||||
{
|
||||
var child = t.GetChild(childIndex);
|
||||
child.gameObject.SetActive(false);
|
||||
StripMesh(child.gameObject);
|
||||
}
|
||||
|
||||
// If no model specified, we're done; return success.
|
||||
if (string.IsNullOrEmpty(renderModelName))
|
||||
return true;
|
||||
|
||||
var renderModels = holder.instance;
|
||||
if (renderModels == null)
|
||||
return false;
|
||||
|
||||
var count = renderModels.GetComponentCount(renderModelName);
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var capacity = renderModels.GetComponentName(renderModelName, (uint)i, null, 0);
|
||||
if (capacity == 0)
|
||||
continue;
|
||||
|
||||
System.Text.StringBuilder componentNameStringBuilder = new System.Text.StringBuilder((int)capacity);
|
||||
if (renderModels.GetComponentName(renderModelName, (uint)i, componentNameStringBuilder, capacity) == 0)
|
||||
continue;
|
||||
|
||||
string componentName = componentNameStringBuilder.ToString();
|
||||
|
||||
// Create (or reuse) a child object for this component (some components are dynamic and don't have meshes).
|
||||
t = FindTransformByName(componentName);
|
||||
if (t != null)
|
||||
{
|
||||
t.gameObject.SetActive(true);
|
||||
componentAttachPoints[componentName] = FindTransformByName(k_localTransformName, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = new GameObject(componentName).transform;
|
||||
t.parent = transform;
|
||||
t.gameObject.layer = gameObject.layer;
|
||||
|
||||
// Also create a child 'attach' object for attaching things.
|
||||
var attach = new GameObject(k_localTransformName).transform;
|
||||
attach.parent = t;
|
||||
attach.localPosition = Vector3.zero;
|
||||
attach.localRotation = Quaternion.identity;
|
||||
attach.localScale = Vector3.one;
|
||||
attach.gameObject.layer = gameObject.layer;
|
||||
|
||||
componentAttachPoints[componentName] = attach;
|
||||
}
|
||||
|
||||
// Reset transform.
|
||||
t.localPosition = Vector3.zero;
|
||||
t.localRotation = Quaternion.identity;
|
||||
t.localScale = Vector3.one;
|
||||
|
||||
capacity = renderModels.GetComponentRenderModelName(renderModelName, componentName, null, 0);
|
||||
if (capacity == 0)
|
||||
continue;
|
||||
|
||||
var componentRenderModelNameStringBuilder = new System.Text.StringBuilder((int)capacity);
|
||||
if (renderModels.GetComponentRenderModelName(renderModelName, componentName, componentRenderModelNameStringBuilder, capacity) == 0)
|
||||
continue;
|
||||
|
||||
string componentRenderModelName = componentRenderModelNameStringBuilder.ToString();
|
||||
|
||||
// Check the cache or load into memory.
|
||||
var model = models[componentRenderModelName] as RenderModel;
|
||||
if (model == null || model.mesh == null)
|
||||
{
|
||||
if (verbose)
|
||||
Debug.Log("<b>[SteamVR]</b> Loading render model " + componentRenderModelName);
|
||||
|
||||
model = LoadRenderModel(renderModels, componentRenderModelName, renderModelName);
|
||||
if (model == null)
|
||||
continue;
|
||||
|
||||
models[componentRenderModelName] = model;
|
||||
}
|
||||
|
||||
t.gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
|
||||
MeshRenderer newRenderer = t.gameObject.AddComponent<MeshRenderer>();
|
||||
newRenderer.sharedMaterial = model.material;
|
||||
meshRenderers.Add(newRenderer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SteamVR_Events.Action deviceConnectedAction, hideRenderModelsAction, modelSkinSettingsHaveChangedAction;
|
||||
|
||||
SteamVR_RenderModel()
|
||||
{
|
||||
deviceConnectedAction = SteamVR_Events.DeviceConnectedAction(OnDeviceConnected);
|
||||
hideRenderModelsAction = SteamVR_Events.HideRenderModelsAction(OnHideRenderModels);
|
||||
modelSkinSettingsHaveChangedAction = SteamVR_Events.SystemAction(EVREventType.VREvent_ModelSkinSettingsHaveChanged, OnModelSkinSettingsHaveChanged);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
#endif
|
||||
if (!string.IsNullOrEmpty(modelOverride))
|
||||
{
|
||||
Debug.Log("<b>[SteamVR]</b> " + modelOverrideWarning);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var system = OpenVR.System;
|
||||
if (system != null && system.IsTrackedDeviceConnected((uint)index))
|
||||
{
|
||||
UpdateModel();
|
||||
}
|
||||
|
||||
deviceConnectedAction.enabled = true;
|
||||
hideRenderModelsAction.enabled = true;
|
||||
modelSkinSettingsHaveChangedAction.enabled = true;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
#endif
|
||||
deviceConnectedAction.enabled = false;
|
||||
hideRenderModelsAction.enabled = false;
|
||||
modelSkinSettingsHaveChangedAction.enabled = false;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Hashtable values;
|
||||
#endif
|
||||
void Update()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
// See if anything has changed since this gets called whenever anything gets touched.
|
||||
var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
|
||||
|
||||
bool modified = false;
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
modified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var f in fields)
|
||||
{
|
||||
if (!values.Contains(f))
|
||||
{
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
|
||||
var v0 = values[f];
|
||||
var v1 = f.GetValue(this);
|
||||
if (v1 != null)
|
||||
{
|
||||
if (!v1.Equals(v0))
|
||||
{
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (v0 != null)
|
||||
{
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modified)
|
||||
{
|
||||
if (renderModelName != modelOverride)
|
||||
{
|
||||
renderModelName = modelOverride;
|
||||
SetModel(modelOverride);
|
||||
}
|
||||
|
||||
values = new Hashtable();
|
||||
foreach (var f in fields)
|
||||
values[f] = f.GetValue(this);
|
||||
}
|
||||
|
||||
return; // Do not update transforms (below) when not playing in Editor (to avoid keeping OpenVR running all the time).
|
||||
}
|
||||
#endif
|
||||
// Update component transforms dynamically.
|
||||
if (updateDynamically)
|
||||
UpdateComponents(OpenVR.RenderModels);
|
||||
}
|
||||
|
||||
Dictionary<int, string> nameCache;
|
||||
|
||||
public void UpdateComponents(CVRRenderModels renderModels)
|
||||
{
|
||||
if (renderModels == null)
|
||||
return;
|
||||
|
||||
if (transform.childCount == 0)
|
||||
return;
|
||||
|
||||
if (nameCache == null)
|
||||
nameCache = new Dictionary<int, string>();
|
||||
|
||||
for (int childIndex = 0; childIndex < transform.childCount; childIndex++)
|
||||
{
|
||||
Transform child = transform.GetChild(childIndex);
|
||||
|
||||
// Cache names since accessing an object's name allocates memory.
|
||||
string componentName;
|
||||
if (!nameCache.TryGetValue(child.GetInstanceID(), out componentName))
|
||||
{
|
||||
componentName = child.name;
|
||||
nameCache.Add(child.GetInstanceID(), componentName);
|
||||
}
|
||||
|
||||
var componentState = new RenderModel_ComponentState_t();
|
||||
if (!renderModels.GetComponentStateForDevicePath(renderModelName, componentName, SteamVR_Input_Source.GetHandle(inputSource), ref controllerModeState, ref componentState))
|
||||
continue;
|
||||
|
||||
child.localPosition = componentState.mTrackingToComponentRenderModel.GetPosition();
|
||||
child.localRotation = componentState.mTrackingToComponentRenderModel.GetRotation();
|
||||
|
||||
Transform attach = null;
|
||||
for (int childChildIndex = 0; childChildIndex < child.childCount; childChildIndex++)
|
||||
{
|
||||
Transform childChild = child.GetChild(childChildIndex);
|
||||
int childInstanceID = childChild.GetInstanceID();
|
||||
string childName;
|
||||
if (!nameCache.TryGetValue(childInstanceID, out childName))
|
||||
{
|
||||
childName = childChild.name;
|
||||
nameCache.Add(childInstanceID, componentName);
|
||||
}
|
||||
|
||||
if (childName == SteamVR_RenderModel.k_localTransformName)
|
||||
attach = childChild;
|
||||
}
|
||||
|
||||
if (attach != null)
|
||||
{
|
||||
attach.position = transform.TransformPoint(componentState.mTrackingToComponentLocal.GetPosition());
|
||||
attach.rotation = transform.rotation * componentState.mTrackingToComponentLocal.GetRotation();
|
||||
|
||||
initializedAttachPoints = true;
|
||||
}
|
||||
|
||||
bool visible = (componentState.uProperties & (uint)EVRComponentProperty.IsVisible) != 0;
|
||||
if (visible != child.gameObject.activeSelf)
|
||||
{
|
||||
child.gameObject.SetActive(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDeviceIndex(int newIndex)
|
||||
{
|
||||
this.index = (SteamVR_TrackedObject.EIndex)newIndex;
|
||||
|
||||
modelOverride = "";
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
UpdateModel();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInputSource(SteamVR_Input_Sources newInputSource)
|
||||
{
|
||||
inputSource = newInputSource;
|
||||
}
|
||||
|
||||
private static void Sleep()
|
||||
{
|
||||
#if !UNITY_METRO
|
||||
//System.Threading.Thread.SpinWait(1); //faster napping
|
||||
System.Threading.Thread.Sleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to handle the inconvenient fact that the packing for RenderModel_t is
|
||||
/// different on Linux/OSX (4) than it is on Windows (8)
|
||||
/// </summary>
|
||||
/// <param name="pRenderModel">native pointer to the RenderModel_t</param>
|
||||
/// <returns></returns>
|
||||
private RenderModel_t MarshalRenderModel(System.IntPtr pRenderModel)
|
||||
{
|
||||
if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
|
||||
(System.Environment.OSVersion.Platform == System.PlatformID.Unix))
|
||||
{
|
||||
var packedModel = (RenderModel_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t_Packed));
|
||||
RenderModel_t model = new RenderModel_t();
|
||||
packedModel.Unpack(ref model);
|
||||
return model;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (RenderModel_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to handle the inconvenient fact that the packing for RenderModel_TextureMap_t is
|
||||
/// different on Linux/OSX (4) than it is on Windows (8)
|
||||
/// </summary>
|
||||
/// <param name="pRenderModel">native pointer to the RenderModel_TextureMap_t</param>
|
||||
/// <returns></returns>
|
||||
private RenderModel_TextureMap_t MarshalRenderModel_TextureMap(System.IntPtr pRenderModel)
|
||||
{
|
||||
if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
|
||||
(System.Environment.OSVersion.Platform == System.PlatformID.Unix))
|
||||
{
|
||||
var packedModel = (RenderModel_TextureMap_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t_Packed));
|
||||
RenderModel_TextureMap_t model = new RenderModel_TextureMap_t();
|
||||
packedModel.Unpack(ref model);
|
||||
return model;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (RenderModel_TextureMap_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_RenderModel.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_RenderModel.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5890e3cad70bea64d91aef9145ba3454
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
236
Assets/SteamVR/Scripts/SteamVR_RingBuffer.cs
Normal file
236
Assets/SteamVR/Scripts/SteamVR_RingBuffer.cs
Normal file
@ -0,0 +1,236 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_RingBuffer<T>
|
||||
{
|
||||
public static bool UseDateTimeForTicks = false;
|
||||
|
||||
protected T[] buffer;
|
||||
protected int currentIndex;
|
||||
protected T lastElement;
|
||||
|
||||
public SteamVR_RingBuffer(int size)
|
||||
{
|
||||
buffer = new T[size];
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
public void Add(T newElement)
|
||||
{
|
||||
buffer[currentIndex] = newElement;
|
||||
|
||||
StepForward();
|
||||
}
|
||||
|
||||
public virtual void StepForward()
|
||||
{
|
||||
lastElement = buffer[currentIndex];
|
||||
|
||||
currentIndex++;
|
||||
if (currentIndex >= buffer.Length)
|
||||
currentIndex = 0;
|
||||
|
||||
cleared = false;
|
||||
}
|
||||
|
||||
public virtual T GetAtIndex(int atIndex)
|
||||
{
|
||||
if (atIndex < 0)
|
||||
atIndex += buffer.Length;
|
||||
|
||||
return buffer[atIndex];
|
||||
}
|
||||
|
||||
public virtual T GetLast()
|
||||
{
|
||||
return lastElement;
|
||||
}
|
||||
|
||||
public virtual int GetLastIndex()
|
||||
{
|
||||
int lastIndex = currentIndex - 1;
|
||||
if (lastIndex < 0)
|
||||
lastIndex += buffer.Length;
|
||||
|
||||
return lastIndex;
|
||||
}
|
||||
|
||||
private bool cleared = false;
|
||||
public void Clear()
|
||||
{
|
||||
if (cleared == true)
|
||||
return;
|
||||
|
||||
if (buffer == null)
|
||||
return;
|
||||
|
||||
for (int index = 0; index < buffer.Length; index++)
|
||||
{
|
||||
buffer[index] = default(T);
|
||||
}
|
||||
|
||||
lastElement = default(T);
|
||||
|
||||
currentIndex = 0;
|
||||
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class SteamVR_HistoryBuffer : SteamVR_RingBuffer<SteamVR_HistoryStep>
|
||||
{
|
||||
public SteamVR_HistoryBuffer(int size) : base(size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Update(Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)
|
||||
{
|
||||
if (buffer[currentIndex] == null)
|
||||
buffer[currentIndex] = new SteamVR_HistoryStep();
|
||||
|
||||
buffer[currentIndex].position = position;
|
||||
buffer[currentIndex].rotation = rotation;
|
||||
buffer[currentIndex].velocity = velocity;
|
||||
buffer[currentIndex].angularVelocity = angularVelocity;
|
||||
|
||||
if (UseDateTimeForTicks)
|
||||
buffer[currentIndex].timeInTicks = System.DateTime.Now.Ticks;
|
||||
else
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
buffer[currentIndex].timeInTicks = (long)(Time.realtimeSinceStartupAsDouble * 1000);
|
||||
#else
|
||||
buffer[currentIndex].timeInTicks = (long)(Time.realtimeSinceStartup * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
StepForward();
|
||||
}
|
||||
|
||||
public float GetVelocityMagnitudeTrend(int toIndex = -1, int fromIndex = -1)
|
||||
{
|
||||
if (toIndex == -1)
|
||||
toIndex = currentIndex - 1;
|
||||
|
||||
if (toIndex < 0)
|
||||
toIndex += buffer.Length;
|
||||
|
||||
if (fromIndex == -1)
|
||||
fromIndex = toIndex - 1;
|
||||
|
||||
if (fromIndex < 0)
|
||||
fromIndex += buffer.Length;
|
||||
|
||||
SteamVR_HistoryStep toStep = buffer[toIndex];
|
||||
SteamVR_HistoryStep fromStep = buffer[fromIndex];
|
||||
|
||||
if (IsValid(toStep) && IsValid(fromStep))
|
||||
{
|
||||
return toStep.velocity.sqrMagnitude - fromStep.velocity.sqrMagnitude;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool IsValid(SteamVR_HistoryStep step)
|
||||
{
|
||||
return step != null && step.timeInTicks != -1;
|
||||
}
|
||||
|
||||
public int GetTopVelocity(int forFrames, int addFrames = 0)
|
||||
{
|
||||
int topFrame = currentIndex;
|
||||
float topVelocitySqr = 0;
|
||||
|
||||
int currentFrame = currentIndex;
|
||||
|
||||
while (forFrames > 0)
|
||||
{
|
||||
forFrames--;
|
||||
currentFrame--;
|
||||
|
||||
if (currentFrame < 0)
|
||||
currentFrame = buffer.Length - 1;
|
||||
|
||||
SteamVR_HistoryStep currentStep = buffer[currentFrame];
|
||||
|
||||
if (IsValid(currentStep) == false)
|
||||
break;
|
||||
|
||||
float currentSqr = buffer[currentFrame].velocity.sqrMagnitude;
|
||||
if (currentSqr > topVelocitySqr)
|
||||
{
|
||||
topFrame = currentFrame;
|
||||
topVelocitySqr = currentSqr;
|
||||
}
|
||||
}
|
||||
|
||||
topFrame += addFrames;
|
||||
|
||||
if (topFrame >= buffer.Length)
|
||||
topFrame -= buffer.Length;
|
||||
|
||||
return topFrame;
|
||||
}
|
||||
|
||||
public void GetAverageVelocities(out Vector3 velocity, out Vector3 angularVelocity, int forFrames, int startFrame = -1)
|
||||
{
|
||||
velocity = Vector3.zero;
|
||||
angularVelocity = Vector3.zero;
|
||||
|
||||
if (startFrame == -1)
|
||||
startFrame = currentIndex - 1;
|
||||
|
||||
if (startFrame < 0)
|
||||
startFrame = buffer.Length - 1;
|
||||
|
||||
int endFrame = startFrame - forFrames;
|
||||
|
||||
if (endFrame < 0)
|
||||
endFrame += buffer.Length;
|
||||
|
||||
Vector3 totalVelocity = Vector3.zero;
|
||||
Vector3 totalAngularVelocity = Vector3.zero;
|
||||
float totalFrames = 0;
|
||||
int currentFrame = startFrame;
|
||||
while (forFrames > 0)
|
||||
{
|
||||
forFrames--;
|
||||
currentFrame--;
|
||||
|
||||
if (currentFrame < 0)
|
||||
currentFrame = buffer.Length - 1;
|
||||
|
||||
SteamVR_HistoryStep currentStep = buffer[currentFrame];
|
||||
|
||||
if (IsValid(currentStep) == false)
|
||||
break;
|
||||
|
||||
totalFrames++;
|
||||
|
||||
totalVelocity += currentStep.velocity;
|
||||
totalAngularVelocity += currentStep.angularVelocity;
|
||||
}
|
||||
|
||||
velocity = totalVelocity / totalFrames;
|
||||
angularVelocity = totalAngularVelocity / totalFrames;
|
||||
}
|
||||
}
|
||||
|
||||
public class SteamVR_HistoryStep
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
|
||||
public Vector3 velocity;
|
||||
|
||||
public Vector3 angularVelocity;
|
||||
|
||||
public long timeInTicks = -1;
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_RingBuffer.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_RingBuffer.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68724c1151b69be48b992a00fd8d9b6b
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
185
Assets/SteamVR/Scripts/SteamVR_Settings.cs
Normal file
185
Assets/SteamVR/Scripts/SteamVR_Settings.cs
Normal file
@ -0,0 +1,185 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Settings : ScriptableObject
|
||||
{
|
||||
private static SteamVR_Settings _instance;
|
||||
public static SteamVR_Settings instance
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadInstance();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public bool pauseGameWhenDashboardVisible = true;
|
||||
public bool lockPhysicsUpdateRateToRenderFrequency = true;
|
||||
public ETrackingUniverseOrigin trackingSpace
|
||||
{
|
||||
get
|
||||
{
|
||||
return trackingSpaceOrigin;
|
||||
}
|
||||
set
|
||||
{
|
||||
trackingSpaceOrigin = value;
|
||||
if (SteamVR_Behaviour.isPlaying)
|
||||
SteamVR_Action_Pose.SetTrackingUniverseOrigin(trackingSpaceOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAsAttribute("trackingSpace")]
|
||||
private ETrackingUniverseOrigin trackingSpaceOrigin = ETrackingUniverseOrigin.TrackingUniverseStanding;
|
||||
|
||||
[Tooltip("Filename local to StreamingAssets/SteamVR/ folder")]
|
||||
public string actionsFilePath = "actions.json";
|
||||
|
||||
[Tooltip("Path local to the directory the SteamVR folder as in")]
|
||||
public string steamVRInputPath = "SteamVR_Input";
|
||||
|
||||
public SteamVR_UpdateModes inputUpdateMode = SteamVR_UpdateModes.OnUpdate;
|
||||
public SteamVR_UpdateModes poseUpdateMode = SteamVR_UpdateModes.OnPreCull;
|
||||
|
||||
public bool activateFirstActionSetOnStart = true;
|
||||
|
||||
[Tooltip("This is the app key the unity editor will use to identify your application. (can be \"steam.app.[appid]\" to persist bindings between editor steam)")]
|
||||
public string editorAppKey;
|
||||
|
||||
[Tooltip("The SteamVR Plugin can automatically make sure VR is enabled in your player settings and if not, enable it.")]
|
||||
public bool autoEnableVR = true;
|
||||
|
||||
[Space()]
|
||||
[Tooltip("This determines if we use legacy mixed reality mode (3rd controller/tracker device connected) or the new input system mode (pose / input source)")]
|
||||
public bool legacyMixedRealityCamera = true;
|
||||
|
||||
[Tooltip("[NON-LEGACY] This is the pose action that will be used for positioning a mixed reality camera if connected")]
|
||||
public SteamVR_Action_Pose mixedRealityCameraPose = SteamVR_Input.GetPoseAction("ExternalCamera");
|
||||
|
||||
[Tooltip("[NON-LEGACY] This is the input source to check on the pose for the mixed reality camera")]
|
||||
public SteamVR_Input_Sources mixedRealityCameraInputSource = SteamVR_Input_Sources.Camera;
|
||||
|
||||
[Tooltip("[NON-LEGACY] Auto enable mixed reality action set if file exists")]
|
||||
public bool mixedRealityActionSetAutoEnable = true;
|
||||
|
||||
[Tooltip("[EDITOR ONLY] The (left) prefab to be used for showing previews while posing hands")]
|
||||
public GameObject previewHandLeft;
|
||||
|
||||
[Tooltip("[EDITOR ONLY] The (right) prefab to be used for showing previews while posing hands")]
|
||||
public GameObject previewHandRight;
|
||||
|
||||
|
||||
private const string previewLeftDefaultAssetName = "vr_glove_left_model_slim";
|
||||
private const string previewRightDefaultAssetName = "vr_glove_right_model_slim";
|
||||
|
||||
|
||||
public bool IsInputUpdateMode(SteamVR_UpdateModes tocheck)
|
||||
{
|
||||
return (inputUpdateMode & tocheck) == tocheck;
|
||||
}
|
||||
public bool IsPoseUpdateMode(SteamVR_UpdateModes tocheck)
|
||||
{
|
||||
return (poseUpdateMode & tocheck) == tocheck;
|
||||
}
|
||||
|
||||
public static void VerifyScriptableObject()
|
||||
{
|
||||
LoadInstance();
|
||||
}
|
||||
|
||||
private static void LoadInstance()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = Resources.Load<SteamVR_Settings>("SteamVR_Settings");
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = SteamVR_Settings.CreateInstance<SteamVR_Settings>();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
string localFolderPath = SteamVR.GetSteamVRResourcesFolderPath(true);
|
||||
string assetPath = System.IO.Path.Combine(localFolderPath, "SteamVR_Settings.asset");
|
||||
|
||||
UnityEditor.AssetDatabase.CreateAsset(_instance, assetPath);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
#endif
|
||||
}
|
||||
|
||||
SetDefaultsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(instance);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
#endif
|
||||
}
|
||||
|
||||
private const string defaultSettingsAssetName = "SteamVR_Settings";
|
||||
|
||||
private static void SetDefaultsIfNeeded()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_instance.editorAppKey))
|
||||
{
|
||||
_instance.editorAppKey = SteamVR.GenerateAppKey();
|
||||
Debug.Log("<b>[SteamVR Setup]</b> Generated you an editor app key of: " + _instance.editorAppKey + ". This lets the editor tell SteamVR what project this is. Has no effect on builds. This can be changed in Assets/SteamVR/Resources/SteamVR_Settings");
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(_instance);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (_instance.previewHandLeft == null)
|
||||
_instance.previewHandLeft = FindDefaultPreviewHand(previewLeftDefaultAssetName);
|
||||
|
||||
if (_instance.previewHandRight == null)
|
||||
_instance.previewHandRight = FindDefaultPreviewHand(previewRightDefaultAssetName);
|
||||
#endif
|
||||
|
||||
#if OPENVR_XR_API
|
||||
Unity.XR.OpenVR.OpenVRSettings settings = Unity.XR.OpenVR.OpenVRSettings.GetSettings();
|
||||
settings.ActionManifestFileRelativeFilePath = SteamVR_Input.GetActionsFilePath();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
settings.EditorAppKey = _instance.editorAppKey;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
private static GameObject FindDefaultPreviewHand(string assetName)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string[] defaultPaths = UnityEditor.AssetDatabase.FindAssets(string.Format("t:Prefab {0}", assetName));
|
||||
if (defaultPaths != null && defaultPaths.Length > 0)
|
||||
{
|
||||
string defaultGUID = defaultPaths[0];
|
||||
string defaultPath = UnityEditor.AssetDatabase.GUIDToAssetPath(defaultGUID);
|
||||
GameObject defaultAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(defaultPath);
|
||||
|
||||
if (defaultAsset == null)
|
||||
Debug.LogError("[SteamVR] Could not load default hand preview prefab: " + assetName + ". Found path: " + defaultPath);
|
||||
|
||||
return defaultAsset;
|
||||
}
|
||||
//else //todo: this will generally fail on the first try but will try again before its an issue.
|
||||
//Debug.LogError("[SteamVR] Could not load default hand preview prefab: " + assetName);
|
||||
#endif
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Settings.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Settings.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7f99b5209bd86441a74f3b0c7aab951
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
118
Assets/SteamVR/Scripts/SteamVR_Skybox.cs
Normal file
118
Assets/SteamVR/Scripts/SteamVR_Skybox.cs
Normal file
@ -0,0 +1,118 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Sets cubemap to use in the compositor.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_Skybox : MonoBehaviour
|
||||
{
|
||||
// Note: Unity's Left and Right Skybox shader variables are switched.
|
||||
public Texture front, back, left, right, top, bottom;
|
||||
|
||||
public enum CellSize
|
||||
{
|
||||
x1024, x64, x32, x16, x8
|
||||
}
|
||||
public CellSize StereoCellSize = CellSize.x32;
|
||||
|
||||
public float StereoIpdMm = 64.0f;
|
||||
|
||||
public void SetTextureByIndex(int i, Texture t)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
front = t;
|
||||
break;
|
||||
case 1:
|
||||
back = t;
|
||||
break;
|
||||
case 2:
|
||||
left = t;
|
||||
break;
|
||||
case 3:
|
||||
right = t;
|
||||
break;
|
||||
case 4:
|
||||
top = t;
|
||||
break;
|
||||
case 5:
|
||||
bottom = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Texture GetTextureByIndex(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
return front;
|
||||
case 1:
|
||||
return back;
|
||||
case 2:
|
||||
return left;
|
||||
case 3:
|
||||
return right;
|
||||
case 4:
|
||||
return top;
|
||||
case 5:
|
||||
return bottom;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public void SetOverride(
|
||||
Texture front = null,
|
||||
Texture back = null,
|
||||
Texture left = null,
|
||||
Texture right = null,
|
||||
Texture top = null,
|
||||
Texture bottom = null)
|
||||
{
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
{
|
||||
var handles = new Texture[] { front, back, left, right, top, bottom };
|
||||
var textures = new Texture_t[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
textures[i].handle = (handles[i] != null) ? handles[i].GetNativeTexturePtr() : System.IntPtr.Zero;
|
||||
textures[i].eType = SteamVR.instance.textureType;
|
||||
textures[i].eColorSpace = EColorSpace.Auto;
|
||||
}
|
||||
var error = compositor.SetSkyboxOverride(textures);
|
||||
if (error != EVRCompositorError.None)
|
||||
{
|
||||
Debug.LogError("<b>[SteamVR]</b> Failed to set skybox override with error: " + error);
|
||||
if (error == EVRCompositorError.TextureIsOnWrongDevice)
|
||||
Debug.Log("<b>[SteamVR]</b> Set your graphics driver to use the same video card as the headset is plugged into for Unity.");
|
||||
else if (error == EVRCompositorError.TextureUsesUnsupportedFormat)
|
||||
Debug.Log("<b>[SteamVR]</b> Ensure skybox textures are not compressed and have no mipmaps.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public void ClearOverride()
|
||||
{
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
compositor.ClearSkyboxOverride();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
SetOverride(front, back, left, right, top, bottom);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
ClearOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Skybox.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Skybox.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13a43e992568b8e48b4bd489b9d96f40
|
||||
timeCreated: 1544852189
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
42
Assets/SteamVR/Scripts/SteamVR_SphericalProjection.cs
Normal file
42
Assets/SteamVR/Scripts/SteamVR_SphericalProjection.cs
Normal file
@ -0,0 +1,42 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Applies spherical projection to output.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class SteamVR_SphericalProjection : MonoBehaviour
|
||||
{
|
||||
static Material material;
|
||||
|
||||
public void Set(Vector3 N,
|
||||
float phi0, float phi1, float theta0, float theta1, // in degrees
|
||||
Vector3 uAxis, Vector3 uOrigin, float uScale,
|
||||
Vector3 vAxis, Vector3 vOrigin, float vScale)
|
||||
{
|
||||
if (material == null)
|
||||
material = new Material(Shader.Find("Custom/SteamVR_SphericalProjection"));
|
||||
|
||||
material.SetVector("_N", new Vector4(N.x, N.y, N.z));
|
||||
material.SetFloat("_Phi0", phi0 * Mathf.Deg2Rad);
|
||||
material.SetFloat("_Phi1", phi1 * Mathf.Deg2Rad);
|
||||
material.SetFloat("_Theta0", theta0 * Mathf.Deg2Rad + Mathf.PI / 2);
|
||||
material.SetFloat("_Theta1", theta1 * Mathf.Deg2Rad + Mathf.PI / 2);
|
||||
material.SetVector("_UAxis", uAxis);
|
||||
material.SetVector("_VAxis", vAxis);
|
||||
material.SetVector("_UOrigin", uOrigin);
|
||||
material.SetVector("_VOrigin", vOrigin);
|
||||
material.SetFloat("_UScale", uScale);
|
||||
material.SetFloat("_VScale", vScale);
|
||||
}
|
||||
|
||||
void OnRenderImage(RenderTexture src, RenderTexture dest)
|
||||
{
|
||||
Graphics.Blit(src, dest, material);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_SphericalProjection.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_SphericalProjection.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f4097fabec5d2b4da2b861750319952
|
||||
timeCreated: 1544852190
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
220
Assets/SteamVR/Scripts/SteamVR_TrackedCamera.cs
Normal file
220
Assets/SteamVR/Scripts/SteamVR_TrackedCamera.cs
Normal file
@ -0,0 +1,220 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Provides access to video feed and poses of tracked cameras.
|
||||
//
|
||||
// Usage:
|
||||
// var source = SteamVR_TrackedCamera.Distorted();
|
||||
// var source = SteamVR_TrackedCamera.Undistorted();
|
||||
// or
|
||||
// var undistorted = true; // or false
|
||||
// var source = SteamVR_TrackedCamera.Source(undistorted);
|
||||
//
|
||||
// - Distorted feeds are the decoded images from the camera.
|
||||
// - Undistorted feeds correct for the camera lens distortion (a.k.a. fisheye)
|
||||
// to make straight lines straight.
|
||||
//
|
||||
// VideoStreamTexture objects must be symmetrically Acquired and Released to
|
||||
// ensure the video stream is activated, and shutdown properly once there are
|
||||
// no more consumers. You only need to Acquire once when starting to use a
|
||||
// stream, and Release when you are done using it (as opposed to every frame).
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_TrackedCamera
|
||||
{
|
||||
public class VideoStreamTexture
|
||||
{
|
||||
public VideoStreamTexture(uint deviceIndex, bool undistorted)
|
||||
{
|
||||
this.undistorted = undistorted;
|
||||
videostream = Stream(deviceIndex);
|
||||
}
|
||||
public bool undistorted { get; private set; }
|
||||
public uint deviceIndex { get { return videostream.deviceIndex; } }
|
||||
public bool hasCamera { get { return videostream.hasCamera; } }
|
||||
public bool hasTracking { get { Update(); return header.trackedDevicePose.bPoseIsValid; } }
|
||||
public uint frameId { get { Update(); return header.nFrameSequence; } }
|
||||
public VRTextureBounds_t frameBounds { get; private set; }
|
||||
public EVRTrackedCameraFrameType frameType { get { return undistorted ? EVRTrackedCameraFrameType.Undistorted : EVRTrackedCameraFrameType.Distorted; } }
|
||||
|
||||
Texture2D _texture;
|
||||
public Texture2D texture { get { Update(); return _texture; } }
|
||||
|
||||
public SteamVR_Utils.RigidTransform transform { get { Update(); return new SteamVR_Utils.RigidTransform(header.trackedDevicePose.mDeviceToAbsoluteTracking); } }
|
||||
public Vector3 velocity { get { Update(); var pose = header.trackedDevicePose; return new Vector3(pose.vVelocity.v0, pose.vVelocity.v1, -pose.vVelocity.v2); } }
|
||||
public Vector3 angularVelocity { get { Update(); var pose = header.trackedDevicePose; return new Vector3(-pose.vAngularVelocity.v0, -pose.vAngularVelocity.v1, pose.vAngularVelocity.v2); } }
|
||||
|
||||
public TrackedDevicePose_t GetPose() { Update(); return header.trackedDevicePose; }
|
||||
|
||||
public ulong Acquire()
|
||||
{
|
||||
return videostream.Acquire();
|
||||
}
|
||||
public ulong Release()
|
||||
{
|
||||
var result = videostream.Release();
|
||||
|
||||
if (videostream.handle == 0)
|
||||
{
|
||||
Object.Destroy(_texture);
|
||||
_texture = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int prevFrameCount = -1;
|
||||
void Update()
|
||||
{
|
||||
if (Time.frameCount == prevFrameCount)
|
||||
return;
|
||||
|
||||
prevFrameCount = Time.frameCount;
|
||||
|
||||
if (videostream.handle == 0)
|
||||
return;
|
||||
|
||||
var vr = SteamVR.instance;
|
||||
if (vr == null)
|
||||
return;
|
||||
|
||||
var trackedCamera = OpenVR.TrackedCamera;
|
||||
if (trackedCamera == null)
|
||||
return;
|
||||
|
||||
var nativeTex = System.IntPtr.Zero;
|
||||
var deviceTexture = (_texture != null) ? _texture : new Texture2D(2, 2);
|
||||
var headerSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(header.GetType());
|
||||
|
||||
if (vr.textureType == ETextureType.OpenGL)
|
||||
{
|
||||
if (glTextureId != 0)
|
||||
trackedCamera.ReleaseVideoStreamTextureGL(videostream.handle, glTextureId);
|
||||
|
||||
if (trackedCamera.GetVideoStreamTextureGL(videostream.handle, frameType, ref glTextureId, ref header, headerSize) != EVRTrackedCameraError.None)
|
||||
return;
|
||||
|
||||
nativeTex = (System.IntPtr)glTextureId;
|
||||
}
|
||||
else if (vr.textureType == ETextureType.DirectX)
|
||||
{
|
||||
if (trackedCamera.GetVideoStreamTextureD3D11(videostream.handle, frameType, deviceTexture.GetNativeTexturePtr(), ref nativeTex, ref header, headerSize) != EVRTrackedCameraError.None)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_texture == null)
|
||||
{
|
||||
_texture = Texture2D.CreateExternalTexture((int)header.nWidth, (int)header.nHeight, TextureFormat.RGBA32, false, false, nativeTex);
|
||||
|
||||
uint width = 0, height = 0;
|
||||
var frameBounds = new VRTextureBounds_t();
|
||||
if (trackedCamera.GetVideoStreamTextureSize(deviceIndex, frameType, ref frameBounds, ref width, ref height) == EVRTrackedCameraError.None)
|
||||
{
|
||||
// Account for textures being upside-down in Unity.
|
||||
frameBounds.vMin = 1.0f - frameBounds.vMin;
|
||||
frameBounds.vMax = 1.0f - frameBounds.vMax;
|
||||
this.frameBounds = frameBounds;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_texture.UpdateExternalTexture(nativeTex);
|
||||
}
|
||||
}
|
||||
|
||||
uint glTextureId;
|
||||
VideoStream videostream;
|
||||
CameraVideoStreamFrameHeader_t header;
|
||||
}
|
||||
|
||||
#region Top level accessors.
|
||||
|
||||
public static VideoStreamTexture Distorted(int deviceIndex = (int)OpenVR.k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
if (distorted == null)
|
||||
distorted = new VideoStreamTexture[OpenVR.k_unMaxTrackedDeviceCount];
|
||||
if (distorted[deviceIndex] == null)
|
||||
distorted[deviceIndex] = new VideoStreamTexture((uint)deviceIndex, false);
|
||||
return distorted[deviceIndex];
|
||||
}
|
||||
|
||||
public static VideoStreamTexture Undistorted(int deviceIndex = (int)OpenVR.k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
if (undistorted == null)
|
||||
undistorted = new VideoStreamTexture[OpenVR.k_unMaxTrackedDeviceCount];
|
||||
if (undistorted[deviceIndex] == null)
|
||||
undistorted[deviceIndex] = new VideoStreamTexture((uint)deviceIndex, true);
|
||||
return undistorted[deviceIndex];
|
||||
}
|
||||
|
||||
public static VideoStreamTexture Source(bool undistorted, int deviceIndex = (int)OpenVR.k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
return undistorted ? Undistorted(deviceIndex) : Distorted(deviceIndex);
|
||||
}
|
||||
|
||||
private static VideoStreamTexture[] distorted, undistorted;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal class to manage lifetime of video streams (per device).
|
||||
|
||||
class VideoStream
|
||||
{
|
||||
public VideoStream(uint deviceIndex)
|
||||
{
|
||||
this.deviceIndex = deviceIndex;
|
||||
var trackedCamera = OpenVR.TrackedCamera;
|
||||
if (trackedCamera != null)
|
||||
trackedCamera.HasCamera(deviceIndex, ref _hasCamera);
|
||||
}
|
||||
public uint deviceIndex { get; private set; }
|
||||
|
||||
ulong _handle;
|
||||
public ulong handle { get { return _handle; } }
|
||||
|
||||
bool _hasCamera;
|
||||
public bool hasCamera { get { return _hasCamera; } }
|
||||
|
||||
ulong refCount;
|
||||
public ulong Acquire()
|
||||
{
|
||||
if (_handle == 0 && hasCamera)
|
||||
{
|
||||
var trackedCamera = OpenVR.TrackedCamera;
|
||||
if (trackedCamera != null)
|
||||
trackedCamera.AcquireVideoStreamingService(deviceIndex, ref _handle);
|
||||
}
|
||||
return ++refCount;
|
||||
}
|
||||
public ulong Release()
|
||||
{
|
||||
if (refCount > 0 && --refCount == 0 && _handle != 0)
|
||||
{
|
||||
var trackedCamera = OpenVR.TrackedCamera;
|
||||
if (trackedCamera != null)
|
||||
trackedCamera.ReleaseVideoStreamingService(_handle);
|
||||
_handle = 0;
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
}
|
||||
|
||||
static VideoStream Stream(uint deviceIndex)
|
||||
{
|
||||
if (videostreams == null)
|
||||
videostreams = new VideoStream[OpenVR.k_unMaxTrackedDeviceCount];
|
||||
if (videostreams[deviceIndex] == null)
|
||||
videostreams[deviceIndex] = new VideoStream(deviceIndex);
|
||||
return videostreams[deviceIndex];
|
||||
}
|
||||
|
||||
static VideoStream[] videostreams;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_TrackedCamera.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_TrackedCamera.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55da3adbb5d30254c97687991608dda0
|
||||
timeCreated: 1544852190
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
112
Assets/SteamVR/Scripts/SteamVR_TrackedObject.cs
Normal file
112
Assets/SteamVR/Scripts/SteamVR_TrackedObject.cs
Normal file
@ -0,0 +1,112 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: For controlling in-game objects with tracked devices.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_TrackedObject : MonoBehaviour
|
||||
{
|
||||
public enum EIndex
|
||||
{
|
||||
None = -1,
|
||||
Hmd = (int)OpenVR.k_unTrackedDeviceIndex_Hmd,
|
||||
Device1,
|
||||
Device2,
|
||||
Device3,
|
||||
Device4,
|
||||
Device5,
|
||||
Device6,
|
||||
Device7,
|
||||
Device8,
|
||||
Device9,
|
||||
Device10,
|
||||
Device11,
|
||||
Device12,
|
||||
Device13,
|
||||
Device14,
|
||||
Device15,
|
||||
Device16
|
||||
}
|
||||
|
||||
public EIndex index;
|
||||
|
||||
[Tooltip("If not set, relative to parent")]
|
||||
public Transform origin;
|
||||
|
||||
public bool isValid { get; private set; }
|
||||
|
||||
private void OnNewPoses(TrackedDevicePose_t[] poses)
|
||||
{
|
||||
if (index == EIndex.None)
|
||||
return;
|
||||
|
||||
var i = (int)index;
|
||||
|
||||
isValid = false;
|
||||
if (poses.Length <= i)
|
||||
return;
|
||||
|
||||
if (!poses[i].bDeviceIsConnected)
|
||||
return;
|
||||
|
||||
if (!poses[i].bPoseIsValid)
|
||||
return;
|
||||
|
||||
isValid = true;
|
||||
|
||||
var pose = new SteamVR_Utils.RigidTransform(poses[i].mDeviceToAbsoluteTracking);
|
||||
|
||||
if (origin != null)
|
||||
{
|
||||
transform.position = origin.transform.TransformPoint(pose.pos);
|
||||
transform.rotation = origin.rotation * pose.rot;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.localPosition = pose.pos;
|
||||
transform.localRotation = pose.rot;
|
||||
}
|
||||
}
|
||||
|
||||
SteamVR_Events.Action newPosesAction;
|
||||
|
||||
SteamVR_TrackedObject()
|
||||
{
|
||||
newPosesAction = SteamVR_Events.NewPosesAction(OnNewPoses);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var render = SteamVR_Render.instance;
|
||||
if (render == null)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
newPosesAction.enabled = true;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
newPosesAction.enabled = false;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
public void SetDeviceIndex(int index)
|
||||
{
|
||||
if (System.Enum.IsDefined(typeof(EIndex), index))
|
||||
this.index = (EIndex)index;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_TrackedObject.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_TrackedObject.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d37c2cf88f7c59f4c8cf5d3812568143
|
||||
timeCreated: 1544852190
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
63
Assets/SteamVR/Scripts/SteamVR_TrackingReferenceManager.cs
Normal file
63
Assets/SteamVR/Scripts/SteamVR_TrackingReferenceManager.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Valve.VR
|
||||
{
|
||||
public class SteamVR_TrackingReferenceManager : MonoBehaviour
|
||||
{
|
||||
private Dictionary<uint, TrackingReferenceObject> trackingReferences = new Dictionary<uint, TrackingReferenceObject>();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
SteamVR_Events.NewPoses.AddListener(OnNewPoses);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SteamVR_Events.NewPoses.RemoveListener(OnNewPoses);
|
||||
}
|
||||
|
||||
private void OnNewPoses(TrackedDevicePose_t[] poses)
|
||||
{
|
||||
if (poses == null)
|
||||
return;
|
||||
|
||||
for (uint deviceIndex = 0; deviceIndex < poses.Length; deviceIndex++)
|
||||
{
|
||||
if (trackingReferences.ContainsKey(deviceIndex) == false)
|
||||
{
|
||||
ETrackedDeviceClass deviceClass = OpenVR.System.GetTrackedDeviceClass(deviceIndex);
|
||||
|
||||
if (deviceClass == ETrackedDeviceClass.TrackingReference)
|
||||
{
|
||||
TrackingReferenceObject trackingReference = new TrackingReferenceObject();
|
||||
trackingReference.trackedDeviceClass = deviceClass;
|
||||
trackingReference.gameObject = new GameObject("Tracking Reference " + deviceIndex.ToString());
|
||||
trackingReference.gameObject.transform.parent = this.transform;
|
||||
trackingReference.trackedObject = trackingReference.gameObject.AddComponent<SteamVR_TrackedObject>();
|
||||
trackingReference.renderModel = trackingReference.gameObject.AddComponent<SteamVR_RenderModel>();
|
||||
trackingReference.renderModel.createComponents = false;
|
||||
trackingReference.renderModel.updateDynamically = false;
|
||||
|
||||
trackingReferences.Add(deviceIndex, trackingReference);
|
||||
|
||||
trackingReference.gameObject.SendMessage("SetDeviceIndex", (int)deviceIndex, SendMessageOptions.DontRequireReceiver);
|
||||
}
|
||||
else
|
||||
{
|
||||
trackingReferences.Add(deviceIndex, new TrackingReferenceObject() { trackedDeviceClass = deviceClass });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TrackingReferenceObject
|
||||
{
|
||||
public ETrackedDeviceClass trackedDeviceClass;
|
||||
public GameObject gameObject;
|
||||
public SteamVR_RenderModel renderModel;
|
||||
public SteamVR_TrackedObject trackedObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2578089a96464b348a5399c795afc7b7
|
||||
timeCreated: 1550629200
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
712
Assets/SteamVR/Scripts/SteamVR_Utils.cs
Normal file
712
Assets/SteamVR/Scripts/SteamVR_Utils.cs
Normal file
@ -0,0 +1,712 @@
|
||||
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
||||
//
|
||||
// Purpose: Utilities for working with SteamVR
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
using Valve.VR;
|
||||
using System.IO;
|
||||
|
||||
public static class SteamVR_Utils
|
||||
{
|
||||
public class Event
|
||||
{
|
||||
public delegate void Handler(params object[] args);
|
||||
|
||||
public static void Listen(string message, Handler action)
|
||||
{
|
||||
var actions = listeners[message] as Handler;
|
||||
if (actions != null)
|
||||
{
|
||||
listeners[message] = actions + action;
|
||||
}
|
||||
else
|
||||
{
|
||||
listeners[message] = action;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Remove(string message, Handler action)
|
||||
{
|
||||
var actions = listeners[message] as Handler;
|
||||
if (actions != null)
|
||||
{
|
||||
listeners[message] = actions - action;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Send(string message, params object[] args)
|
||||
{
|
||||
var actions = listeners[message] as Handler;
|
||||
if (actions != null)
|
||||
{
|
||||
actions(args);
|
||||
}
|
||||
}
|
||||
|
||||
private static Hashtable listeners = new Hashtable();
|
||||
}
|
||||
|
||||
|
||||
public static bool IsValid(Vector3 vector)
|
||||
{
|
||||
return (float.IsNaN(vector.x) == false && float.IsNaN(vector.y) == false && float.IsNaN(vector.z) == false);
|
||||
}
|
||||
public static bool IsValid(Quaternion rotation)
|
||||
{
|
||||
return (float.IsNaN(rotation.x) == false && float.IsNaN(rotation.y) == false && float.IsNaN(rotation.z) == false && float.IsNaN(rotation.w) == false) &&
|
||||
(rotation.x != 0 || rotation.y != 0 || rotation.z != 0 || rotation.w != 0);
|
||||
}
|
||||
|
||||
// this version does not clamp [0..1]
|
||||
public static Quaternion Slerp(Quaternion A, Quaternion B, float t)
|
||||
{
|
||||
var cosom = Mathf.Clamp(A.x * B.x + A.y * B.y + A.z * B.z + A.w * B.w, -1.0f, 1.0f);
|
||||
if (cosom < 0.0f)
|
||||
{
|
||||
B = new Quaternion(-B.x, -B.y, -B.z, -B.w);
|
||||
cosom = -cosom;
|
||||
}
|
||||
|
||||
float sclp, sclq;
|
||||
if ((1.0f - cosom) > 0.0001f)
|
||||
{
|
||||
var omega = Mathf.Acos(cosom);
|
||||
var sinom = Mathf.Sin(omega);
|
||||
sclp = Mathf.Sin((1.0f - t) * omega) / sinom;
|
||||
sclq = Mathf.Sin(t * omega) / sinom;
|
||||
}
|
||||
else
|
||||
{
|
||||
// "from" and "to" very close, so do linear interp
|
||||
sclp = 1.0f - t;
|
||||
sclq = t;
|
||||
}
|
||||
|
||||
return new Quaternion(
|
||||
sclp * A.x + sclq * B.x,
|
||||
sclp * A.y + sclq * B.y,
|
||||
sclp * A.z + sclq * B.z,
|
||||
sclp * A.w + sclq * B.w);
|
||||
}
|
||||
|
||||
public static Vector3 Lerp(Vector3 A, Vector3 B, float t)
|
||||
{
|
||||
return new Vector3(
|
||||
Lerp(A.x, B.x, t),
|
||||
Lerp(A.y, B.y, t),
|
||||
Lerp(A.z, B.z, t));
|
||||
}
|
||||
|
||||
public static float Lerp(float A, float B, float t)
|
||||
{
|
||||
return A + (B - A) * t;
|
||||
}
|
||||
|
||||
public static double Lerp(double A, double B, double t)
|
||||
{
|
||||
return A + (B - A) * t;
|
||||
}
|
||||
|
||||
public static float InverseLerp(Vector3 A, Vector3 B, Vector3 result)
|
||||
{
|
||||
return Vector3.Dot(result - A, B - A);
|
||||
}
|
||||
|
||||
public static float InverseLerp(float A, float B, float result)
|
||||
{
|
||||
return (result - A) / (B - A);
|
||||
}
|
||||
|
||||
public static double InverseLerp(double A, double B, double result)
|
||||
{
|
||||
return (result - A) / (B - A);
|
||||
}
|
||||
|
||||
public static float Saturate(float A)
|
||||
{
|
||||
return (A < 0) ? 0 : (A > 1) ? 1 : A;
|
||||
}
|
||||
|
||||
public static Vector2 Saturate(Vector2 A)
|
||||
{
|
||||
return new Vector2(Saturate(A.x), Saturate(A.y));
|
||||
}
|
||||
|
||||
public static float Abs(float A)
|
||||
{
|
||||
return (A < 0) ? -A : A;
|
||||
}
|
||||
|
||||
public static Vector2 Abs(Vector2 A)
|
||||
{
|
||||
return new Vector2(Abs(A.x), Abs(A.y));
|
||||
}
|
||||
|
||||
private static float _copysign(float sizeval, float signval)
|
||||
{
|
||||
return Mathf.Sign(signval) == 1 ? Mathf.Abs(sizeval) : -Mathf.Abs(sizeval);
|
||||
}
|
||||
|
||||
public static Quaternion GetRotation(this Matrix4x4 matrix)
|
||||
{
|
||||
Quaternion q = new Quaternion();
|
||||
q.w = Mathf.Sqrt(Mathf.Max(0, 1 + matrix.m00 + matrix.m11 + matrix.m22)) / 2;
|
||||
q.x = Mathf.Sqrt(Mathf.Max(0, 1 + matrix.m00 - matrix.m11 - matrix.m22)) / 2;
|
||||
q.y = Mathf.Sqrt(Mathf.Max(0, 1 - matrix.m00 + matrix.m11 - matrix.m22)) / 2;
|
||||
q.z = Mathf.Sqrt(Mathf.Max(0, 1 - matrix.m00 - matrix.m11 + matrix.m22)) / 2;
|
||||
q.x = _copysign(q.x, matrix.m21 - matrix.m12);
|
||||
q.y = _copysign(q.y, matrix.m02 - matrix.m20);
|
||||
q.z = _copysign(q.z, matrix.m10 - matrix.m01);
|
||||
return q;
|
||||
}
|
||||
|
||||
public static Vector3 GetPosition(this Matrix4x4 matrix)
|
||||
{
|
||||
var x = matrix.m03;
|
||||
var y = matrix.m13;
|
||||
var z = matrix.m23;
|
||||
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public static Vector3 GetScale(this Matrix4x4 m)
|
||||
{
|
||||
var x = Mathf.Sqrt(m.m00 * m.m00 + m.m01 * m.m01 + m.m02 * m.m02);
|
||||
var y = Mathf.Sqrt(m.m10 * m.m10 + m.m11 * m.m11 + m.m12 * m.m12);
|
||||
var z = Mathf.Sqrt(m.m20 * m.m20 + m.m21 * m.m21 + m.m22 * m.m22);
|
||||
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public static float GetLossyScale(Transform t)
|
||||
{
|
||||
return t.lossyScale.x;
|
||||
}
|
||||
|
||||
private const string secretKey = "foobar";
|
||||
|
||||
public static string GetBadMD5Hash(string usedString)
|
||||
{
|
||||
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(usedString + secretKey);
|
||||
|
||||
return GetBadMD5Hash(bytes);
|
||||
}
|
||||
public static string GetBadMD5Hash(byte[] bytes)
|
||||
{
|
||||
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
|
||||
byte[] hash = md5.ComputeHash(bytes);
|
||||
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
for (int i = 0; i < hash.Length; i++)
|
||||
{
|
||||
sb.Append(hash[i].ToString("x2"));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
public static string GetBadMD5HashFromFile(string filePath)
|
||||
{
|
||||
if (File.Exists(filePath) == false)
|
||||
return null;
|
||||
|
||||
string data = File.ReadAllText(filePath);
|
||||
return GetBadMD5Hash(data + secretKey);
|
||||
}
|
||||
|
||||
public static string SanitizePath(string path, bool allowLeadingSlash = true)
|
||||
{
|
||||
if (path.Contains("\\\\"))
|
||||
path = path.Replace("\\\\", "\\");
|
||||
if (path.Contains("//"))
|
||||
path = path.Replace("//", "/");
|
||||
|
||||
if (allowLeadingSlash == false)
|
||||
{
|
||||
if (path[0] == '/' || path[0] == '\\')
|
||||
path = path.Substring(1);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static System.Type FindType(string typeName)
|
||||
{
|
||||
var type = System.Type.GetType(typeName);
|
||||
if (type != null) return type;
|
||||
foreach (var a in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
type = a.GetType(typeName);
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct RigidTransform
|
||||
{
|
||||
public Vector3 pos;
|
||||
public Quaternion rot;
|
||||
|
||||
public static RigidTransform identity
|
||||
{
|
||||
get { return new RigidTransform(Vector3.zero, Quaternion.identity); }
|
||||
}
|
||||
|
||||
public static RigidTransform FromLocal(Transform t)
|
||||
{
|
||||
return new RigidTransform(t.localPosition, t.localRotation);
|
||||
}
|
||||
|
||||
public RigidTransform(Vector3 pos, Quaternion rot)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.rot = rot;
|
||||
}
|
||||
|
||||
public RigidTransform(Transform t)
|
||||
{
|
||||
this.pos = t.position;
|
||||
this.rot = t.rotation;
|
||||
}
|
||||
|
||||
public RigidTransform(Transform from, Transform to)
|
||||
{
|
||||
var inv = Quaternion.Inverse(from.rotation);
|
||||
rot = inv * to.rotation;
|
||||
pos = inv * (to.position - from.position);
|
||||
}
|
||||
|
||||
public RigidTransform(HmdMatrix34_t pose)
|
||||
{
|
||||
var m = Matrix4x4.identity;
|
||||
|
||||
m[0, 0] = pose.m0;
|
||||
m[0, 1] = pose.m1;
|
||||
m[0, 2] = -pose.m2;
|
||||
m[0, 3] = pose.m3;
|
||||
|
||||
m[1, 0] = pose.m4;
|
||||
m[1, 1] = pose.m5;
|
||||
m[1, 2] = -pose.m6;
|
||||
m[1, 3] = pose.m7;
|
||||
|
||||
m[2, 0] = -pose.m8;
|
||||
m[2, 1] = -pose.m9;
|
||||
m[2, 2] = pose.m10;
|
||||
m[2, 3] = -pose.m11;
|
||||
|
||||
this.pos = m.GetPosition();
|
||||
this.rot = m.GetRotation();
|
||||
}
|
||||
|
||||
public RigidTransform(HmdMatrix44_t pose)
|
||||
{
|
||||
var m = Matrix4x4.identity;
|
||||
|
||||
m[0, 0] = pose.m0;
|
||||
m[0, 1] = pose.m1;
|
||||
m[0, 2] = -pose.m2;
|
||||
m[0, 3] = pose.m3;
|
||||
|
||||
m[1, 0] = pose.m4;
|
||||
m[1, 1] = pose.m5;
|
||||
m[1, 2] = -pose.m6;
|
||||
m[1, 3] = pose.m7;
|
||||
|
||||
m[2, 0] = -pose.m8;
|
||||
m[2, 1] = -pose.m9;
|
||||
m[2, 2] = pose.m10;
|
||||
m[2, 3] = -pose.m11;
|
||||
|
||||
m[3, 0] = pose.m12;
|
||||
m[3, 1] = pose.m13;
|
||||
m[3, 2] = -pose.m14;
|
||||
m[3, 3] = pose.m15;
|
||||
|
||||
this.pos = m.GetPosition();
|
||||
this.rot = m.GetRotation();
|
||||
}
|
||||
|
||||
public HmdMatrix44_t ToHmdMatrix44()
|
||||
{
|
||||
var m = Matrix4x4.TRS(pos, rot, Vector3.one);
|
||||
var pose = new HmdMatrix44_t();
|
||||
|
||||
pose.m0 = m[0, 0];
|
||||
pose.m1 = m[0, 1];
|
||||
pose.m2 = -m[0, 2];
|
||||
pose.m3 = m[0, 3];
|
||||
|
||||
pose.m4 = m[1, 0];
|
||||
pose.m5 = m[1, 1];
|
||||
pose.m6 = -m[1, 2];
|
||||
pose.m7 = m[1, 3];
|
||||
|
||||
pose.m8 = -m[2, 0];
|
||||
pose.m9 = -m[2, 1];
|
||||
pose.m10 = m[2, 2];
|
||||
pose.m11 = -m[2, 3];
|
||||
|
||||
pose.m12 = m[3, 0];
|
||||
pose.m13 = m[3, 1];
|
||||
pose.m14 = -m[3, 2];
|
||||
pose.m15 = m[3, 3];
|
||||
|
||||
return pose;
|
||||
}
|
||||
|
||||
public HmdMatrix34_t ToHmdMatrix34()
|
||||
{
|
||||
var m = Matrix4x4.TRS(pos, rot, Vector3.one);
|
||||
var pose = new HmdMatrix34_t();
|
||||
|
||||
pose.m0 = m[0, 0];
|
||||
pose.m1 = m[0, 1];
|
||||
pose.m2 = -m[0, 2];
|
||||
pose.m3 = m[0, 3];
|
||||
|
||||
pose.m4 = m[1, 0];
|
||||
pose.m5 = m[1, 1];
|
||||
pose.m6 = -m[1, 2];
|
||||
pose.m7 = m[1, 3];
|
||||
|
||||
pose.m8 = -m[2, 0];
|
||||
pose.m9 = -m[2, 1];
|
||||
pose.m10 = m[2, 2];
|
||||
pose.m11 = -m[2, 3];
|
||||
|
||||
return pose;
|
||||
}
|
||||
|
||||
public override bool Equals(object o)
|
||||
{
|
||||
if (o is RigidTransform)
|
||||
{
|
||||
RigidTransform t = (RigidTransform)o;
|
||||
return pos == t.pos && rot == t.rot;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return pos.GetHashCode() ^ rot.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(RigidTransform a, RigidTransform b)
|
||||
{
|
||||
return a.pos == b.pos && a.rot == b.rot;
|
||||
}
|
||||
|
||||
public static bool operator !=(RigidTransform a, RigidTransform b)
|
||||
{
|
||||
return a.pos != b.pos || a.rot != b.rot;
|
||||
}
|
||||
|
||||
public static RigidTransform operator *(RigidTransform a, RigidTransform b)
|
||||
{
|
||||
return new RigidTransform
|
||||
{
|
||||
rot = a.rot * b.rot,
|
||||
pos = a.pos + a.rot * b.pos
|
||||
};
|
||||
}
|
||||
|
||||
public void Inverse()
|
||||
{
|
||||
rot = Quaternion.Inverse(rot);
|
||||
pos = -(rot * pos);
|
||||
}
|
||||
|
||||
public RigidTransform GetInverse()
|
||||
{
|
||||
var t = new RigidTransform(pos, rot);
|
||||
t.Inverse();
|
||||
return t;
|
||||
}
|
||||
|
||||
public void Multiply(RigidTransform a, RigidTransform b)
|
||||
{
|
||||
rot = a.rot * b.rot;
|
||||
pos = a.pos + a.rot * b.pos;
|
||||
}
|
||||
|
||||
public Vector3 InverseTransformPoint(Vector3 point)
|
||||
{
|
||||
return Quaternion.Inverse(rot) * (point - pos);
|
||||
}
|
||||
|
||||
public Vector3 TransformPoint(Vector3 point)
|
||||
{
|
||||
return pos + (rot * point);
|
||||
}
|
||||
|
||||
public static Vector3 operator *(RigidTransform t, Vector3 v)
|
||||
{
|
||||
return t.TransformPoint(v);
|
||||
}
|
||||
|
||||
public static RigidTransform Interpolate(RigidTransform a, RigidTransform b, float t)
|
||||
{
|
||||
return new RigidTransform(Vector3.Lerp(a.pos, b.pos, t), Quaternion.Slerp(a.rot, b.rot, t));
|
||||
}
|
||||
|
||||
public void Interpolate(RigidTransform to, float t)
|
||||
{
|
||||
pos = SteamVR_Utils.Lerp(pos, to.pos, t);
|
||||
rot = SteamVR_Utils.Slerp(rot, to.rot, t);
|
||||
}
|
||||
}
|
||||
|
||||
public delegate object SystemFn(CVRSystem system, params object[] args);
|
||||
|
||||
public static object CallSystemFn(SystemFn fn, params object[] args)
|
||||
{
|
||||
var initOpenVR = (!SteamVR.active && !SteamVR.usingNativeSupport);
|
||||
if (initOpenVR)
|
||||
{
|
||||
var error = EVRInitError.None;
|
||||
OpenVR.Init(ref error, EVRApplicationType.VRApplication_Utility);
|
||||
}
|
||||
|
||||
var system = OpenVR.System;
|
||||
var result = (system != null) ? fn(system, args) : null;
|
||||
|
||||
if (initOpenVR)
|
||||
OpenVR.Shutdown();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void TakeStereoScreenshot(uint screenshotHandle, GameObject target, int cellSize, float ipd, ref string previewFilename, ref string VRFilename)
|
||||
{
|
||||
const int width = 4096;
|
||||
const int height = width / 2;
|
||||
const int halfHeight = height / 2;
|
||||
|
||||
var texture = new Texture2D(width, height * 2, TextureFormat.ARGB32, false);
|
||||
|
||||
var timer = new System.Diagnostics.Stopwatch();
|
||||
|
||||
Camera tempCamera = null;
|
||||
|
||||
timer.Start();
|
||||
|
||||
var camera = target.GetComponent<Camera>();
|
||||
if (camera == null)
|
||||
{
|
||||
if (tempCamera == null)
|
||||
tempCamera = new GameObject().AddComponent<Camera>();
|
||||
camera = tempCamera;
|
||||
}
|
||||
|
||||
// Render preview texture
|
||||
const int previewWidth = 2048;
|
||||
const int previewHeight = 2048;
|
||||
var previewTexture = new Texture2D(previewWidth, previewHeight, TextureFormat.ARGB32, false);
|
||||
var targetPreviewTexture = new RenderTexture(previewWidth, previewHeight, 24);
|
||||
|
||||
var oldTargetTexture = camera.targetTexture;
|
||||
var oldOrthographic = camera.orthographic;
|
||||
var oldFieldOfView = camera.fieldOfView;
|
||||
var oldAspect = camera.aspect;
|
||||
var oldstereoTargetEye = camera.stereoTargetEye;
|
||||
camera.stereoTargetEye = StereoTargetEyeMask.None;
|
||||
camera.fieldOfView = 60.0f;
|
||||
camera.orthographic = false;
|
||||
camera.targetTexture = targetPreviewTexture;
|
||||
camera.aspect = 1.0f;
|
||||
camera.Render();
|
||||
|
||||
// copy preview texture
|
||||
RenderTexture.active = targetPreviewTexture;
|
||||
previewTexture.ReadPixels(new Rect(0, 0, targetPreviewTexture.width, targetPreviewTexture.height), 0, 0);
|
||||
RenderTexture.active = null;
|
||||
camera.targetTexture = null;
|
||||
Object.DestroyImmediate(targetPreviewTexture);
|
||||
|
||||
var fx = camera.gameObject.AddComponent<SteamVR_SphericalProjection>();
|
||||
|
||||
var oldPosition = target.transform.localPosition;
|
||||
var oldRotation = target.transform.localRotation;
|
||||
var basePosition = target.transform.position;
|
||||
var baseRotation = Quaternion.Euler(0, target.transform.rotation.eulerAngles.y, 0);
|
||||
|
||||
var transform = camera.transform;
|
||||
|
||||
int vTotal = halfHeight / cellSize;
|
||||
float dv = 90.0f / vTotal; // vertical degrees per segment
|
||||
float dvHalf = dv / 2.0f;
|
||||
|
||||
var targetTexture = new RenderTexture(cellSize, cellSize, 24);
|
||||
targetTexture.wrapMode = TextureWrapMode.Clamp;
|
||||
targetTexture.antiAliasing = 8;
|
||||
|
||||
camera.fieldOfView = dv;
|
||||
camera.orthographic = false;
|
||||
camera.targetTexture = targetTexture;
|
||||
camera.aspect = oldAspect;
|
||||
camera.stereoTargetEye = StereoTargetEyeMask.None;
|
||||
|
||||
// Render sections of a sphere using a rectilinear projection
|
||||
// and resample using a sphereical projection into a single panorama
|
||||
// texture per eye. We break into sections in order to keep the eye
|
||||
// separation similar around the sphere. Rendering alternates between
|
||||
// top and bottom sections, sweeping horizontally around the sphere,
|
||||
// alternating left and right eyes.
|
||||
for (int v = 0; v < vTotal; v++)
|
||||
{
|
||||
var pitch = 90.0f - (v * dv) - dvHalf;
|
||||
var uTotal = width / targetTexture.width;
|
||||
var du = 360.0f / uTotal; // horizontal degrees per segment
|
||||
var duHalf = du / 2.0f;
|
||||
|
||||
var vTarget = v * halfHeight / vTotal;
|
||||
|
||||
for (int i = 0; i < 2; i++) // top, bottom
|
||||
{
|
||||
if (i == 1)
|
||||
{
|
||||
pitch = -pitch;
|
||||
vTarget = height - vTarget - cellSize;
|
||||
}
|
||||
|
||||
for (int u = 0; u < uTotal; u++)
|
||||
{
|
||||
var yaw = -180.0f + (u * du) + duHalf;
|
||||
|
||||
var uTarget = u * width / uTotal;
|
||||
|
||||
var vTargetOffset = 0;
|
||||
var xOffset = -ipd / 2 * Mathf.Cos(pitch * Mathf.Deg2Rad);
|
||||
|
||||
for (int j = 0; j < 2; j++) // left, right
|
||||
{
|
||||
if (j == 1)
|
||||
{
|
||||
vTargetOffset = height;
|
||||
xOffset = -xOffset;
|
||||
}
|
||||
|
||||
var offset = baseRotation * Quaternion.Euler(0, yaw, 0) * new Vector3(xOffset, 0, 0);
|
||||
transform.position = basePosition + offset;
|
||||
|
||||
var direction = Quaternion.Euler(pitch, yaw, 0.0f);
|
||||
transform.rotation = baseRotation * direction;
|
||||
|
||||
// vector pointing to center of this section
|
||||
var N = direction * Vector3.forward;
|
||||
|
||||
// horizontal span of this section in degrees
|
||||
var phi0 = yaw - (du / 2);
|
||||
var phi1 = phi0 + du;
|
||||
|
||||
// vertical span of this section in degrees
|
||||
var theta0 = pitch + (dv / 2);
|
||||
var theta1 = theta0 - dv;
|
||||
|
||||
var midPhi = (phi0 + phi1) / 2;
|
||||
var baseTheta = Mathf.Abs(theta0) < Mathf.Abs(theta1) ? theta0 : theta1;
|
||||
|
||||
// vectors pointing to corners of image closes to the equator
|
||||
var V00 = Quaternion.Euler(baseTheta, phi0, 0.0f) * Vector3.forward;
|
||||
var V01 = Quaternion.Euler(baseTheta, phi1, 0.0f) * Vector3.forward;
|
||||
|
||||
// vectors pointing to top and bottom midsection of image
|
||||
var V0M = Quaternion.Euler(theta0, midPhi, 0.0f) * Vector3.forward;
|
||||
var V1M = Quaternion.Euler(theta1, midPhi, 0.0f) * Vector3.forward;
|
||||
|
||||
// intersection points for each of the above
|
||||
var P00 = V00 / Vector3.Dot(V00, N);
|
||||
var P01 = V01 / Vector3.Dot(V01, N);
|
||||
var P0M = V0M / Vector3.Dot(V0M, N);
|
||||
var P1M = V1M / Vector3.Dot(V1M, N);
|
||||
|
||||
// calculate basis vectors for plane
|
||||
var P00_P01 = P01 - P00;
|
||||
var P0M_P1M = P1M - P0M;
|
||||
|
||||
var uMag = P00_P01.magnitude;
|
||||
var vMag = P0M_P1M.magnitude;
|
||||
|
||||
var uScale = 1.0f / uMag;
|
||||
var vScale = 1.0f / vMag;
|
||||
|
||||
var uAxis = P00_P01 * uScale;
|
||||
var vAxis = P0M_P1M * vScale;
|
||||
|
||||
// update material constant buffer
|
||||
fx.Set(N, phi0, phi1, theta0, theta1,
|
||||
uAxis, P00, uScale,
|
||||
vAxis, P0M, vScale);
|
||||
|
||||
camera.aspect = uMag / vMag;
|
||||
camera.Render();
|
||||
|
||||
RenderTexture.active = targetTexture;
|
||||
texture.ReadPixels(new Rect(0, 0, targetTexture.width, targetTexture.height), uTarget, vTarget + vTargetOffset);
|
||||
RenderTexture.active = null;
|
||||
}
|
||||
|
||||
// Update progress
|
||||
var progress = (float)(v * (uTotal * 2.0f) + u + i * uTotal) / (float)(vTotal * (uTotal * 2.0f));
|
||||
OpenVR.Screenshots.UpdateScreenshotProgress(screenshotHandle, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 100% flush
|
||||
OpenVR.Screenshots.UpdateScreenshotProgress(screenshotHandle, 1.0f);
|
||||
|
||||
// Save textures to disk.
|
||||
// Add extensions
|
||||
previewFilename += ".png";
|
||||
VRFilename += ".png";
|
||||
|
||||
// Preview
|
||||
previewTexture.Apply();
|
||||
System.IO.File.WriteAllBytes(previewFilename, previewTexture.EncodeToPNG());
|
||||
|
||||
// VR
|
||||
texture.Apply();
|
||||
System.IO.File.WriteAllBytes(VRFilename, texture.EncodeToPNG());
|
||||
|
||||
// Cleanup.
|
||||
if (camera != tempCamera)
|
||||
{
|
||||
camera.targetTexture = oldTargetTexture;
|
||||
camera.orthographic = oldOrthographic;
|
||||
camera.fieldOfView = oldFieldOfView;
|
||||
camera.aspect = oldAspect;
|
||||
camera.stereoTargetEye = oldstereoTargetEye;
|
||||
|
||||
target.transform.localPosition = oldPosition;
|
||||
target.transform.localRotation = oldRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempCamera.targetTexture = null;
|
||||
}
|
||||
|
||||
Object.DestroyImmediate(targetTexture);
|
||||
Object.DestroyImmediate(fx);
|
||||
|
||||
timer.Stop();
|
||||
Debug.Log(string.Format("Screenshot took {0} seconds.", timer.Elapsed));
|
||||
|
||||
if (tempCamera != null)
|
||||
{
|
||||
Object.DestroyImmediate(tempCamera.gameObject);
|
||||
}
|
||||
|
||||
Object.DestroyImmediate(previewTexture);
|
||||
Object.DestroyImmediate(texture);
|
||||
}
|
||||
}
|
||||
12
Assets/SteamVR/Scripts/SteamVR_Utils.cs.meta
Normal file
12
Assets/SteamVR/Scripts/SteamVR_Utils.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be3c3a084f7b29b4880b42b4cfbf4d8f
|
||||
timeCreated: 1544852190
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user