diff --git a/ZEDCamera/Assets/ZED/Doc/ReleaseNotes.md b/ZEDCamera/Assets/ZED/Doc/ReleaseNotes.md index 2992cafd..40fd6013 100644 --- a/ZEDCamera/Assets/ZED/Doc/ReleaseNotes.md +++ b/ZEDCamera/Assets/ZED/Doc/ReleaseNotes.md @@ -1,16 +1,35 @@ + +### 2.6.0 + * **Features/Bug Fixes**: + - Add WindowsMR support through SteamVR Only (Beta). + - Fixed overwriting old mesh textures when Spatial mapping button is used while Save Mesh is checked. + - Forced pasue state to false when stating a scan in case it's been left in a pause state from a previous scan. + - Fixed restart (not) required when changing post-processing settings. + - Fixed repetitve UI error when not using plugin in VR mode in ZEDControllerTracker.cs. [ssue #21 reported on github]. + + + * **Documentation**: + - Full rework of comments in source code. + + + * **Compatibility**: + - Compatible with ZED SDK 2.5, CUDA 9.0 or 9.2. + + ### 2.5.0 - - **Features**: + * **Features**: - Add USB Headset detection function in non-play mode. - - Improve tracking status with "Camera not tracked" status if no headset connected and camera tracking is disabled + - Improve tracking status with "Camera not tracked" status if no headset connected and camera tracking is disabled. - - **Examples**: - - Add Drone Shooter example. This example reproduces the ZEDWorld drone demo app. - - Add Movie Screen example. This example reproduces the ZEDWorld movie demo app. - - Add VR Only Plane Detection. Advanced plane detection sample to show how the place the bunny and make collisions. + + * **Examples**: + - Add Drone Shooter example. This example reproduces the ZEDWorld drone demo app. + - Add Movie Screen example. This example reproduces the ZEDWorld movie demo app. + - Add VR Only Plane Detection. Advanced plane detection sample to show how the place the bunny and make collisions. - - **Compatibility**: + * **Compatibility**: - Compatible with ZED SDK 2.5, CUDA 9.0 or 9.2. diff --git a/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs b/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs index 6169cddb..fe23200f 100644 --- a/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs +++ b/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs @@ -3,27 +3,30 @@ using UnityEditor; /// -/// Custom inspector :Add a button to the ZEDCameraSettingsEditor at the end of the panel ZEDManager +/// Custom editor used by ZEDManager to extend the default panel shown in the Inspector. +/// Adds the camera status boxes, the button on the bottom to open camera settings, and a button to restart the camera when +/// a settings has changed that requires it. /// [CustomEditor(typeof(ZEDManager)), CanEditMultipleObjects] public class ZEDCameraEditor : Editor { + /// + /// Reference to the ZEDManager instance we're editing. + /// ZEDManager manager; - //Store copies of ZEDManager's fields to detect changes + //Store copies of ZEDManager's fields to detect changes later with CheckChange(). sl.RESOLUTION resolution; sl.DEPTH_MODE depthmode; bool usespatialmemory; - bool usedepthocclusion; - bool usepostprocessing; + bool usedepthocclusion = true; + bool usepostprocessing = true; - bool pendingchange = false; + bool restartneeded = false; private void OnEnable() { - - manager = (ZEDManager)target; resolution = manager.resolution; @@ -35,14 +38,14 @@ private void OnEnable() public override void OnInspectorGUI() { - DrawDefaultInspector(); + DrawDefaultInspector(); //Draws what you'd normally see in the inspector in absense of a custom inspector. if(GUI.changed) { - pendingchange = CheckChange(); + restartneeded = CheckChange(); } - if (Application.isPlaying && manager.IsZEDReady && pendingchange) + if (Application.isPlaying && manager.IsZEDReady && restartneeded) //Checks if we need to restart the camera. { GUILayout.Space(10); @@ -57,18 +60,16 @@ public override void OnInspectorGUI() if (GUILayout.Button("Restart Camera")) { - manager.Reset(); //Reset the ZED + manager.Reset(); //Reset the ZED. - //Reset the fields now that they're synced + //Reset the fields now that they're synced. resolution = manager.resolution; depthmode = manager.depthMode; usespatialmemory = manager.enableSpatialMemory; usepostprocessing = manager.postProcessing; - pendingchange = false; + restartneeded = false; } - - } GUIStyle standardStyle = new GUIStyle(EditorStyles.textField); @@ -77,53 +78,57 @@ public override void OnInspectorGUI() GUILayout.Space(10); - //Status window + //Status window. EditorGUILayout.LabelField("Status", EditorStyles.boldLabel); EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.TextField("SDK Version:", manager.versionZED); - EditorGUILayout.TextField("Engine FPS:", manager.engineFPS); - EditorGUILayout.TextField("Camera FPS:", manager.cameraFPS); - if (manager.IsCameraTracked) - EditorGUILayout.TextField ("Tracking State:", manager.trackingState, standardStyle); + GUIContent sdkversionlabel = new GUIContent("SDK Version:", "Version of the installed ZED SDK."); + EditorGUILayout.TextField(sdkversionlabel, manager.versionZED); + + GUIContent enginefpslabel = new GUIContent("Engine FPS:", "How many frames per second the engine is rendering."); + EditorGUILayout.TextField(enginefpslabel, manager.engineFPS); + + GUIContent camerafpslabel = new GUIContent("Camera FPS:", "How many images per second are received from the ZED."); + EditorGUILayout.TextField(camerafpslabel, manager.cameraFPS); + + GUIContent trackingstatelabel = new GUIContent("Tracking State:", "Whether the ZED's tracking is on, off, or searching (lost position, trying to recover)."); + if (manager.IsCameraTracked || !manager.IsZEDReady) + EditorGUILayout.TextField (trackingstatelabel, manager.trackingState, standardStyle); else - EditorGUILayout.TextField ("Tracking State:", manager.trackingState,errorStyle); - + EditorGUILayout.TextField (trackingstatelabel, manager.trackingState,errorStyle); + GUIContent hmdlabel = new GUIContent("HMD Device:", "The connected VR headset, if any."); if (Application.isPlaying) - EditorGUILayout.TextField ("HMD Device:", manager.HMDDevice); + EditorGUILayout.TextField (hmdlabel, manager.HMDDevice); else { - //Detect through USB + //Detect devices through USB. if (sl.ZEDCamera.CheckUSBDeviceConnected(sl.USB_DEVICE.USB_DEVICE_OCULUS)) - EditorGUILayout.TextField ("HMD Device:", "Oculus USB Detected"); - else if (sl.ZEDCamera.CheckUSBDeviceConnected(sl.USB_DEVICE.USB_DEVICE_OCULUS)) - EditorGUILayout.TextField ("HMD Device:", "HTC USB Detected"); + EditorGUILayout.TextField (hmdlabel, "Oculus USB Detected"); + else if (sl.ZEDCamera.CheckUSBDeviceConnected(sl.USB_DEVICE.USB_DEVICE_HTC)) + EditorGUILayout.TextField (hmdlabel, "HTC USB Detected"); else - EditorGUILayout.TextField ("HMD Device:", "-"); + EditorGUILayout.TextField (hmdlabel, "-"); } EditorGUI.EndDisabledGroup(); GUILayout.Space(20); - if (GUILayout.Button("Open Camera Control")) + GUIContent camcontrolbuttonlabel = new GUIContent("Open Camera Control", "Opens a window for adjusting camera settings like brightness, gain/exposure, etc."); + if (GUILayout.Button(camcontrolbuttonlabel)) { EditorWindow.GetWindow(typeof(ZEDCameraSettingsEditor), false, "ZED Camera").Show(); } - - - } /// - /// Check if something has changed that requires restarting the camera + /// Check if something has changed that requires restarting the camera. + /// Used to know if the Restart Camera button and a prompt to press it should be visible. /// - /// + /// True if a setting was changed that won't go into effect until a restart. private bool CheckChange() { if (resolution != manager.resolution || depthmode != manager.depthMode || - usespatialmemory != manager.enableSpatialMemory || - //usedepthocclusion != manager.depthOcclusion || - usepostprocessing != manager.postProcessing) + usespatialmemory != manager.enableSpatialMemory) { return true; } diff --git a/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraSettingsEditor.cs b/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraSettingsEditor.cs index 0b8a98b0..dbe21111 100644 --- a/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraSettingsEditor.cs +++ b/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDCameraSettingsEditor.cs @@ -4,117 +4,124 @@ using UnityEditor; /// -/// Custom window editor : Displays the information about the ZED. +/// Custom window editor that handles what you see after clicking Window -> ZED Camera in the editor, or +/// the Open Camera Control button in the ZEDManager Inspector. /// public class ZEDCameraSettingsEditor : EditorWindow { /// - /// Brightness default value + /// Brightness default value. /// private const int cbrightness = 4; /// - /// Contrast default value + /// Contrast default value. /// private const int ccontrast = 4; /// - /// Hue default value + /// Hue default value. /// private const int chue = 0; /// - /// Saturation default value + /// Saturation default value. /// private const int csaturation = 4; /// - /// White balance default value + /// White balance default value. /// private const int cwhiteBalance = 2600; /// - /// Path to save data + /// Path to save/load configurations. /// private const string ZEDSettingsPath = "ZED_Settings.conf"; /// - /// Current brightness value + /// Current brightness value. /// static private int brightness = 4; /// - /// Current contrast value + /// Current contrast value. /// static private int contrast = 4; /// - /// Current hue value + /// Current hue value. /// static private int hue = 0; /// - /// Current saturation value + /// Current saturation value. /// static private int saturation = 4; /// - /// Current gain value + /// Current gain value. /// [SerializeField] public int gain; /// - /// Current exposure value + /// Current exposure value. /// [SerializeField] public int exposure; static private int whiteBalance = cwhiteBalance; /// - /// Is the exposure and gain is in auto mode + /// Is the exposure and gain in auto mode? /// [SerializeField] public static bool groupAuto = true; /// - /// Is the whiteBalance is in auto mode + /// Is the white balance in auto mode? /// [SerializeField] public static bool whiteBalanceAuto = true; /// - /// Is data is loaded from the file + /// Has data been loaded from the file? /// [SerializeField] public static bool loaded = false; /// - /// Is a reset is wanted + /// Has the user or a script requested a reset? /// [SerializeField] public bool resetWanted = false; /// - /// Refresh rate of the values of gain and exposure when auto mode is activated + /// Refresh rate of the values of gain and exposure when auto mode is activated. /// private const int refreshRate = 60; + /// + /// Timer used to know when to refresh. + /// static private int refreshCount = 0; /// - /// Sat manual value + /// Whether we've set a manual value to gain and exposure or if they're in auto mode. /// static bool setManualValue = true; + /// + /// Whether we've set a manual value to white balance or if it's in auto mode. + /// static bool setManualWhiteBalance = true; /// - /// default gui + /// Default GUI color. /// static Color defaultColor; + static GUIStyle style = new GUIStyle(); static private GUILayoutOption[] optionsButton = { GUILayout.MaxWidth(100) }; - static private sl.ZEDCamera zedCamera; static int tab = 0; @@ -128,11 +135,18 @@ public class ZEDCameraSettingsEditor : EditorWindow private bool launched = false; + /// + /// Empty Constructor. + /// public ZEDCameraSettingsEditor() { } + /// + /// Updates values from the camera and redraws the elements. + /// Called whenever the application play state changes. + /// void Draw() { if (zedCamera != null && Application.isPlaying) @@ -149,7 +163,7 @@ void Draw() [MenuItem("Window/ZED Camera")] static void Init() { - // Get existing open window or if none, make a new one: + //Gets existing open window or, if none exists, makes a new one. ZEDCameraSettingsEditor window = (ZEDCameraSettingsEditor)EditorWindow.GetWindow(typeof(ZEDCameraSettingsEditor), false, "ZED Camera"); window.position = new Rect(window.position.x, window.position.y, 400, 400); style.normal.textColor = Color.red; @@ -167,7 +181,8 @@ static void Init() } /// - /// Refresh data + /// Refreshes data. Called by Unity when this window gets focus, such as when + /// it's clicked on or alt-tabbed to. /// void OnFocus() { @@ -187,7 +202,7 @@ void OnFocus() } /// - /// Init all the first values, and gets values from the ZED + /// Initializes all the starting values, and gets current values from the ZED. /// void FirstInit() { @@ -413,7 +428,7 @@ void CameraSettingsView() } /// - /// Reset all the values + /// Resets all the values to defaults. Used when pressing the Reset button. /// /// private void ResetValues(bool auto) @@ -433,7 +448,7 @@ private void ResetValues(bool auto) } /// - /// Save the camera settings in a file + /// Saves the camera settings into a file. /// void SaveCameraSettings() { @@ -441,7 +456,7 @@ void SaveCameraSettings() } /// - /// Get the values registered and update the interface + /// Gets the registered values and updates the interface. /// private void UpdateValuesCameraSettings() { @@ -457,7 +472,7 @@ private void UpdateValuesCameraSettings() } /// - /// Load the data from the file and update the current settings + /// Loads the data from the file and updates the current settings. /// void LoadCameraSettings() { @@ -469,6 +484,11 @@ void LoadCameraSettings() loaded = true; } + /// + /// Draws a horizontal label with a label and a box. + /// + /// Text of the label. + /// Value to be displayed. Will be converted to a string. void LabelHorizontal(string name, float value) { GUILayout.BeginHorizontal(); @@ -478,7 +498,7 @@ void LabelHorizontal(string name, float value) } /// - /// Calibration settings view + /// Displays the calibration settings view. /// void CalibrationSettingsView() { diff --git a/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs b/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs index 8e2ad929..4e29d564 100644 --- a/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs +++ b/ZEDCamera/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs @@ -3,8 +3,10 @@ using UnityEngine; using UnityEditor; using System.Collections; + /// -/// Checks if the SDK is well installed +/// Checks your system for the required ZED SDK version, and displays an error window with instructions if it's missing. +/// Runs automatically when Unity loads. Remove the [InitializeOnLoad] tag to disable this. /// [InitializeOnLoad] public class ZEDPluginInspector : EditorWindow @@ -71,7 +73,10 @@ void OnEnable() addMissingTag (); } - + /// + /// Makes sure the project's tags are loaded, as they are used in some samples but may get deleted on import or + /// if shared via source control. + /// static public void addMissingTag() { // Open tag manager @@ -88,8 +93,8 @@ static public void addMissingTag() if (t.stringValue.Equals(s)) { found = true; break; } } - // if not found, add it since we use it in GreenScreen. - // This tag may be used anywhere, since it tags helper object that may have a specific behavior + //If not found, add it since we use it in GreenScreen. + //This tag may be used anywhere, since it tags helper object that may have a specific behavior if (!found) { @@ -175,7 +180,9 @@ void OnGUI() } } - + /// + /// Displays a popup window when the correct ZED SDK version isn't installed. + /// public void showErrorWindow() { if (image == null) { @@ -230,6 +237,10 @@ public void showErrorWindow() Vector2 scrollPosition; + /// + /// Shows a window prompting the user to change project settings to recommended settings, with + /// buttons to automatically do so. + /// public void showSettingsWindow() { if (image == null) { diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scene/Dark Room.unity b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scene/Dark Room.unity index 4279a127..51ba254c 100644 --- a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scene/Dark Room.unity +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scene/Dark Room.unity @@ -77,15 +77,17 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVRFiltering: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousColorSigma: 1 - m_PVRFilteringAtrousNormalSigma: 1 - m_PVRFilteringAtrousPositionSigma: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -410,7 +412,7 @@ GameObject: - component: {fileID: 259196392} - component: {fileID: 259196394} - component: {fileID: 259196393} - - component: {fileID: 259196395} + - component: {fileID: 259196396} m_Layer: 0 m_Name: DiscoBall m_TagString: Untagged @@ -472,7 +474,7 @@ MeshFilter: m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 259196391} m_Mesh: {fileID: 4300000, guid: 37000bced5dd1dd4091ca59f0274bb80, type: 3} ---- !u!114 &259196395 +--- !u!114 &259196396 MonoBehaviour: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} @@ -480,10 +482,12 @@ MonoBehaviour: m_GameObject: {fileID: 259196391} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 28a4a4fb3e37a604798d656ff2fcc2ea, type: 3} + m_Script: {fileID: 11500000, guid: 46b439f5618c4d04684914fe2a698b8f, type: 3} m_Name: m_EditorClassIdentifier: - secondsPerRevolution: 10 + xRevolutionsPerSecond: 0 + yRevolutionsPerSecond: 0.1 + zRevolutionsPerSecond: 0 --- !u!1 &311198984 GameObject: m_ObjectHideFlags: 0 @@ -937,9 +941,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b3d618a95ffb03445b07e260dbe9c87c, type: 3} m_Name: m_EditorClassIdentifier: - SequenceDurationSeconds: 7.6 - _sequenceTimer: -0.3 - SequenceObjects: + sequenceDurationSeconds: 7.6 + sequenceObjects: - {fileID: 2124941620} - {fileID: 1520216781} - {fileID: 1625288869} diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/LightShow.cs b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/LightShow.cs index 42817c08..f6b03484 100644 --- a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/LightShow.cs +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/LightShow.cs @@ -8,17 +8,33 @@ /// public class LightShow : MonoBehaviour { - public float SequenceDurationSeconds = 16; - public float _sequenceTimer = 0; + /// + /// How long each "show" lasts before its object is disabled and the next is enabled. + /// + [Tooltip("How long each 'show' lasts before its object is disabled and the next is enabled. ")] + public float sequenceDurationSeconds = 16; - public List SequenceObjects = new List(); + /// + /// Each object that holds a "show". Should contain or be a parent of all light objects it interacts with. + /// + [Tooltip("Each object that holds a 'show'. Should contain or be a parent of all light objects it interacts with.")] + public List sequenceObjects = new List(); - private int _sequenceIndex = 0; + /// + /// Runtime timer that indicates how long the current 'show' has been active. + /// Update() increments it and advances the show when it reaches sequenceDurationSeconds, then resets it to 0. + /// + private float sequencetimer = 0; + + /// + /// Index of the sequence. Used to advance through the SequenceObjects list. + /// + private int sequenceindex = 0; // Use this for initialization void OnEnable () { - //set the first to active and the rest to not active. + //set the first show to active and the rest to not active. SwitchToSequence(0); } @@ -26,28 +42,28 @@ void OnEnable () // Update is called once per frame void Update () { - _sequenceTimer += Time.deltaTime; - if(_sequenceTimer >= SequenceDurationSeconds) + sequencetimer += Time.deltaTime; + if(sequencetimer >= sequenceDurationSeconds) { - _sequenceIndex++; - if(_sequenceIndex >= SequenceObjects.Count) + sequenceindex++; + if(sequenceindex >= sequenceObjects.Count) { - _sequenceIndex = 0; + sequenceindex = 0; } - SwitchToSequence(_sequenceIndex); - _sequenceTimer = _sequenceTimer % SequenceDurationSeconds; + SwitchToSequence(sequenceindex); + sequencetimer = sequencetimer % sequenceDurationSeconds; } } private void SwitchToSequence(int index) { //Make sure that's a valid index - if (SequenceObjects.Count <= index || SequenceObjects[index] == null) return; + if (sequenceObjects.Count <= index || sequenceObjects[index] == null) return; - for(int i = 0; i < SequenceObjects.Count; i++) + for(int i = 0; i < sequenceObjects.Count; i++) { - SequenceObjects[i].SetActive(i == index); + sequenceObjects[i].SetActive(i == index); } } } diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/PitchOscillator.cs b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/PitchOscillator.cs new file mode 100644 index 00000000..cfe653a5 --- /dev/null +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/PitchOscillator.cs @@ -0,0 +1,60 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +/// +/// Makes an object slide on its X axis according to the AnimationCurve specified. +/// Used in the ZED Dark Room example scene to make lights sweep back and forth. +/// +public class PitchOscillator : MonoBehaviour +{ + /// + /// The path it takes to oscillate. Makes it simple to set a pattern in the Inspector. + /// + [Tooltip("The path it takes to oscillate. Makes it simple to set a pattern in the Inspector. ")] + public AnimationCurve animationCurve; + + /// + /// How long a full oscillation lasts (from start to finish of animationCurve). + /// + [Tooltip("How long a full oscillation lasts (from start to finish of animationCurve). ")] + public float secondsPerOscillation = .95f; + + /// + /// Scales the values in animationCurve, since it's difficult to specify values outside -1 and 1 in the Inspector. + /// + [Tooltip("Scales the values in animationCurve, since it's difficult to specify values outside -1 and 1 in the Inspector. ")] + public float distanceScale = 2; + + /// + /// How long through the animation it has played. + /// Incremented by Time.deltaTime / distanceScale each Update(). + /// + private float timer = 0f; + + /// + /// Cache for the starting position, so oscillations can be done relative to it after it moves. + /// + private Vector3 startposition; //In local space + + // Use this for initialization + void Start () + { + startposition = transform.localPosition; + } + + // Update is called once per frame + void Update () + { + //Update the timer and restart the animationCurve if finished. + timer += Time.deltaTime; + if(timer >= secondsPerOscillation) + { + timer = timer % secondsPerOscillation; + } + + //Move the light according to the curve. + float newxpos = animationCurve.Evaluate(timer / secondsPerOscillation) * distanceScale; + transform.localPosition = startposition + transform.localRotation * Vector3.right * newxpos; + } +} diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirLightManager.cs b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirLightManager.cs index 65734c16..a6c3254e 100644 --- a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirLightManager.cs +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirLightManager.cs @@ -3,27 +3,57 @@ using UnityEngine; /// -/// Every X seconds, changes the lights to a random color and points them in new, random directions. +/// Every X seconds, changes the lights in all child objects to a random (smae) color and rotates them to new, random directions +/// if it contains a RandomDirectionMover object. +/// Used for the ZED Dark Room example scene. /// public class RandomDirLightManager : MonoBehaviour { - public float secondsBetweenPulses = 0.5f; //Seconds between - private float pulseTimer; + /// + /// Time between each pulse. Should match the beats-per-second of the music. + /// + [Tooltip("Time between each pulse. Should match the beats-per-second of the music. ")] + public float secondsBetweenPulses = 0.5f; + /// + /// How long to wait after start to start pulsing. Use to sync to music. + /// + [Tooltip("How long to wait after start to start pulsing. Use to sync to music.")] public float startDelay = 0.1f; - public List ColorOptions = new List(); //Potential colors the lights can become + /// + /// Pool of colors that the lights could become on each pulse. + /// + [Tooltip("Pool of colors that the lights could become on each pulse. ")] + public List ColorOptions = new List(); + + /// + /// Length of time in seconds since the last pulse. + /// Gets incremented by Time.deltaTime in Update(). When it hits secondsBetweenPulses, it triggers a pulse and resets. + /// + private float pulseTimer; + /// + /// List of all Light components in this object and its children. Filled in Start(). + /// private List lightList; - private List randPointerList; + /// + /// List of all RandomDirectionMover components in this object and its children. Filled in Start. + /// + private List randPointerList; + + /// + /// Stores the index of the color we used during the last pulse. + /// Used to prevent the same color appearing twice in a row. + /// private int lastcolorindex = -1; // Use this for initialization void Start () { lightList = new List(GetComponentsInChildren()); - randPointerList = new List(GetComponentsInChildren()); + randPointerList = new List(GetComponentsInChildren()); pulseTimer = -startDelay; } @@ -40,6 +70,9 @@ void Update () } } + /// + /// Picks a random color, sets all Lights to that color, and tells all RandomDirectionMovers to move randomly. + /// private void PulseLights() { if (ColorOptions.Count > 0) //We have at least one color indexed, so we can pick a color from the list. @@ -53,6 +86,8 @@ private void PulseLights() { newcolorindex = Random.Range(0, ColorOptions.Count - 1); } + + lastcolorindex = newcolorindex; } else newcolorindex = 0; @@ -62,10 +97,9 @@ private void PulseLights() } } - foreach(LightRandDir pointer in randPointerList) + foreach(RandomDirectionMover pointer in randPointerList) { - StartCoroutine(pointer.NewDirection()); + StartCoroutine(pointer.NewDirection()); //Causes it to move to a random direction. } - } } diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirectionMover.cs b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirectionMover.cs new file mode 100644 index 00000000..77c9c670 --- /dev/null +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RandomDirectionMover.cs @@ -0,0 +1,39 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +/// +/// Every X seconds, rotates the light to face a new random direction. +/// Used by the ZED Dark Room example scene and called by RandomDirLightManager.cs. +/// +public class RandomDirectionMover : MonoBehaviour +{ + /// + /// How long the light takes to point at a new location. + /// + [Tooltip("How long the light takes to point at a new location. ")] + public float timeToPoint = 0.1f; + + /// + /// Points the object in a new, random direction. + /// Gets called by RandomDirLightManager.cs. + /// + /// + public IEnumerator NewDirection() + { + Vector3 startdir = transform.localRotation * Vector3.forward; + Vector3 randdir = new Vector3(Random.Range(0f, 2f) - 1f, Random.Range(0f, .25f) - .125f, Random.Range(0f, 2f) - 1f); //Weighted towards horizon to make it more likely to be visible + + float angledif = Mathf.Abs(Vector3.Angle(startdir, randdir)); //How we know how quickly to rotate each frame, and when to stop + + Quaternion targetrot = Quaternion.FromToRotation(startdir, randdir); + + for(float t = 0; t < timeToPoint; t += Time.deltaTime) + { + transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetrot, angledif / timeToPoint * Time.deltaTime); + yield return null; + } + + + } +} diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RotateOnAxes.cs b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RotateOnAxes.cs new file mode 100644 index 00000000..f92e8274 --- /dev/null +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/RotateOnAxes.cs @@ -0,0 +1,39 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +/// +/// Rotates the object along its axes consistently. +/// Because its using local axes, it affects the angle of other axes going forward, resulting in wild +/// but possibly desired behavior if multiple axes are rotating at once. +/// Used in the ZED Dark Room example scene to rotate lights. +/// +public class RotateOnAxes : MonoBehaviour +{ + /// + /// How far it spins on the X axis (pitch) per frame. + /// + [Tooltip("How far it spins on the X axis (pitch) per frame. ")] + public float xRevolutionsPerSecond = 0.5f; + + /// + /// How far it spins on the Y axis (yaw) per frame. + /// + [Tooltip("How far it spins on the Y axis (yaw) per frame. ")] + public float yRevolutionsPerSecond = 0.25f; + + /// + /// How far it spins on the Z axis (roll) per frame. + /// + [Tooltip("How far it spins on the Z axis (roll) per frame. ")] + public float zRevolutionsPerSecond = 0; + + // Update is called once per frame + void Update () + { + //Rotate on the axes. Note that the order this occurs is important as each rotation changes transform.localRotation. + transform.Rotate(transform.localRotation * Vector3.right, xRevolutionsPerSecond * 360 * Time.deltaTime); //Pitch + transform.Rotate(transform.localRotation * Vector3.up, yRevolutionsPerSecond * 360 * Time.deltaTime); //Yaw + transform.Rotate(transform.localRotation * Vector3.forward, zRevolutionsPerSecond * 360 * Time.deltaTime); //Roll + } +} diff --git a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/StrobeLight.cs b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/StrobeLight.cs index 0b8f858d..ddecb623 100644 --- a/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/StrobeLight.cs +++ b/ZEDCamera/Assets/ZED/Examples/Dark Room/Scripts/StrobeLight.cs @@ -7,20 +7,45 @@ /// public class StrobeLight : MonoBehaviour { - public float startDelay = 0f; //Gets added to the time before the first flash. - public float secondsBetweenFlashes = 0.25f; //Independent of the actual flash duration. - public float flashDurationInSeconds = 0.1f; //How long the flash stays in the On state. + /// + /// Gets added to the time before the first flash. Use to synchromize with music. + /// + [Tooltip("Gets added to the time before the first flash. Use to synchromize with music. ")] + public float startDelay = 0f; + /// + /// Time between the start of each flash. Independent of the actual flash duration. + /// + [Tooltip("Time between the start of each flash. Independent of the actual flash duration. ")] + public float secondsBetweenFlashes = 0.25f; + + /// + /// How long each flash lasts/stays in the On state. + /// + [Tooltip("How long each flash lasts/stays in the On state. ")] + public float flashDurationInSeconds = 0.1f; + + /// + /// How long in seconds since the last flash. + /// Gets incremented by Time.deltaTime in Update(). Starts a flash and resets when it hits secondsBetweenFlashes. + /// private float flashtimer; + /// + /// The Light attached to this object. + /// private Light lightcomponent; - private float maxintensity; + + /// + /// Cache for the starting intensity, which will be the flash intensity. + /// + private float maxintensity; // Use this for initialization void Start () { lightcomponent = GetComponent(); - maxintensity = lightcomponent.intensity; + maxintensity = lightcomponent.intensity; //Cache the light's intensity. lightcomponent.intensity = 0; flashtimer = -startDelay; //Add the start delay. @@ -38,11 +63,15 @@ void Update () } } + /// + /// Turns on the light, waits for flashDurationInSeconds, then turns it off. + /// + /// private IEnumerator FlashLight() { - lightcomponent.intensity = maxintensity; + lightcomponent.intensity = maxintensity; //Set the light to be as bright as it started. - for(float t = 0; t < flashDurationInSeconds; t += Time.deltaTime) + for(float t = 0; t < flashDurationInSeconds; t += Time.deltaTime) { yield return null; } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Drone.prefab b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Drone.prefab index dd6dba22..4a287485 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Drone.prefab +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Drone.prefab @@ -190,12 +190,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 917f4e739f47fe547b2e6f09043ba809, type: 3} m_Name: m_EditorClassIdentifier: - Speed: 1 - Lifespan: 10 - DistanceBetweenRayChecks: 0.05 - RealWorldThickness: 0.05 + speed: 1 + lifespan: 10 + distanceBetweenRayChecks: 0.05 + realWorldThickness: 0.05 _leftCamera: {fileID: 0} - ExplosionPrefab: {fileID: 1791358933297042, guid: 2c032cea9b945c4419585e346249d2ec, + explosionPrefab: {fileID: 1791358933297042, guid: 2c032cea9b945c4419585e346249d2ec, type: 2} --- !u!114 &114619527117472448 MonoBehaviour: diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Player.prefab b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Player.prefab index dca318fa..4fc30646 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Player.prefab +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/LaserShot_Player.prefab @@ -203,13 +203,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 4d78428ec77d6ef4c81909005135b46f, type: 3} m_Name: m_EditorClassIdentifier: - Speed: 16 - Lifespan: 4 - DistanceBetweenRayChecks: 0.05 - RealWorldThickness: 0.05 + speed: 16 + lifespan: 4 + distanceBetweenRayChecks: 0.05 + realWorldThickness: 0.05 _leftCamera: {fileID: 0} Damage: 10 - ExplosionPrefab: {fileID: 1045759306052250, guid: 75397fce40505504fb362db1229eb57a, + explosionPrefab: {fileID: 1045759306052250, guid: 75397fce40505504fb362db1229eb57a, type: 2} --- !u!198 &198725941130230972 ParticleSystem: diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Left.prefab b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Left.prefab index ac76e1aa..eefbefb0 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Left.prefab +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Left.prefab @@ -320,10 +320,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: deca4f9199ed3eb4daefaa38ac81e7cc, type: 3} m_Name: m_EditorClassIdentifier: - LaserShotPrefab: {fileID: 1300082734421426, guid: e63673e297726e74c80253a7265f6670, + laserShotPrefab: {fileID: 1300082734421426, guid: e63673e297726e74c80253a7265f6670, type: 2} - LaserPointerBeadHolder: {fileID: 1788373281826982} - LaserSpawnLocation: {fileID: 4121785863575496} + laserPointerBeadHolder: {fileID: 1788373281826982} + laserSpawnLocation: {fileID: 4121785863575496} --- !u!114 &114575857264643554 MonoBehaviour: m_ObjectHideFlags: 1 @@ -337,6 +337,7 @@ MonoBehaviour: m_EditorClassIdentifier: deviceToTrack: 1 _latencyCompensation: 78 + SNHolder: --- !u!212 &212080970251524668 SpriteRenderer: m_ObjectHideFlags: 1 diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Right.prefab b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Right.prefab index 863523cb..a2941d06 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Right.prefab +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Prefabs/Simple Laser Gun Right.prefab @@ -322,6 +322,7 @@ MonoBehaviour: m_EditorClassIdentifier: deviceToTrack: 0 _latencyCompensation: 78 + SNHolder: --- !u!114 &114506010654110848 MonoBehaviour: m_ObjectHideFlags: 1 @@ -333,10 +334,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: deca4f9199ed3eb4daefaa38ac81e7cc, type: 3} m_Name: m_EditorClassIdentifier: - LaserShotPrefab: {fileID: 1300082734421426, guid: e63673e297726e74c80253a7265f6670, + laserShotPrefab: {fileID: 1300082734421426, guid: e63673e297726e74c80253a7265f6670, type: 2} - LaserPointerBeadHolder: {fileID: 1720199324786894} - LaserSpawnLocation: {fileID: 4121785863575496} + laserPointerBeadHolder: {fileID: 1720199324786894} + laserSpawnLocation: {fileID: 4121785863575496} --- !u!212 &212511314823844404 SpriteRenderer: m_ObjectHideFlags: 1 diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Resources/Muzzleflash_FX/Materials/No Name.mat b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Resources/Muzzleflash_FX/Materials/No Name.mat new file mode 100644 index 00000000..52859c69 --- /dev/null +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Resources/Muzzleflash_FX/Materials/No Name.mat @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: No Name + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scenes/DroneBattle.unity b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scenes/DroneBattle.unity index 94642ecf..47885125 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scenes/DroneBattle.unity +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scenes/DroneBattle.unity @@ -77,15 +77,17 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVRFiltering: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousColorSigma: 1 - m_PVRFilteringAtrousNormalSigma: 1 - m_PVRFilteringAtrousPositionSigma: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -777,10 +779,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: deca4f9199ed3eb4daefaa38ac81e7cc, type: 3} m_Name: m_EditorClassIdentifier: - LaserShotPrefab: {fileID: 1300082734421426, guid: e63673e297726e74c80253a7265f6670, + laserShotPrefab: {fileID: 1300082734421426, guid: e63673e297726e74c80253a7265f6670, type: 2} - LaserPointerBeadHolder: {fileID: 1888571830} - LaserSpawnLocation: {fileID: 1151804457} + laserPointerBeadHolder: {fileID: 1888571830} + laserSpawnLocation: {fileID: 1151804457} --- !u!82 &1223027083 AudioSource: m_ObjectHideFlags: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/Drone.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/Drone.cs index b508cd2b..7ae06313 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/Drone.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/Drone.cs @@ -5,176 +5,290 @@ public class Drone : MonoBehaviour, ILaserable { - [Tooltip("The Drone's Health Points, synced over the network.")] + /// + /// The Drone's Health Points. + /// + [Tooltip("The Drone's Health Points.")] public int Hitpoints = 100; - [Tooltip("Fire Rate")] + + /// + /// How long between each laser shot. + /// + [Tooltip("How long between each laser shot.e")] public float SecondsBetweenLaserShots = 4f; - [Tooltip("Accuracy of the Shot.")] + + /// + /// Accuracy of each shot. The laser will aim at a random point in a sphere around the user. This value sets that sphere's radius. + /// + [Tooltip("Accuracy of each shot. The laser will aim at a random point in a sphere around the user. This value sets that sphere's radius.")] public float laserAccuracy = 0.5f; + + /// + /// The object spawned when the drone shoots. + /// [Tooltip("The object spawned when the drone shoots.")] public GameObject LaserPrefab; - [Tooltip("The object that gets spawned when the drone dies.")] + + /// + /// The object that gets spawned when the drone dies. Intended to be an explosion. + /// + [Tooltip("The object that gets spawned when the drone dies. Intended to be an explosion.")] public GameObject ExplosionPrefab; - [Tooltip("How smooth is the movement of the drone.")] + + /// + /// How long it takes the drone to move to a new position. + /// + [Tooltip("How long it takes the drone to move to a new position.")] public float smoothTime = 0.75f; - [Tooltip("How far a point must be from real geometry to be considered a valid spawn location.")] + + /// + /// How far a potential movement point must be from real geometry to be considered valid . + /// Set to higher values if the drone is moving into walls or other objects. + /// + [Tooltip("How far a potential movement point must be from real geometry to be considered valid. " + + "Set to higher values if the drone is moving alongside walls or other objects. ")] public float ClearRadius = 2f; - [Tooltip("How many times should we look around our chosen spawnPoint to see if there are any obstacles around it.")] - public int radiusCheckRate = 100; - [Tooltip("The maximum amount of collisions detected near a spawn point allowed.")] - public float percentageThreshold = 0.35f; - [Tooltip("Angle between drone and target to have before turning the drone towards Target.")] + + /// + /// How many times we check near a potential movement point to see if there are any obstacles around it. + /// Higher values make it less likely a drone will move inside an object, but may cause noticeable stutter. + /// + [Tooltip("How many times we check near a potential movement point to see if there are any obstacles around it. " + + "Higher values make it less likely a drone will move inside an object, but may cause noticeable stutter.")] + public int radiusCheckRate = 100; + + /// + /// The maximum amount of collisions detected near a movement point allowed. + /// Higher values make it less likely for a drone to move inside an object, but too high and it may not move at all. + /// + [Tooltip("The maximum amount of collisions detected near a movement point allowed. " + + "Higher values make it less likely for a drone to move inside an object, but too high and it may not move at all.")] + public float percentageThreshold = 0.35f; + + /// + /// Maximum angle between drone and its target to have before the drone will turn to face it. + /// + [Tooltip("Maximum angle between drone and its target to have before the drone will turn to face it.")] public float angleBeforeRotate = 20f; - [Tooltip("AudioClips to play for the Drone: element 0 is for its laser, 1 is for its destruction.")] + + /// + /// "AudioClips to play for the Drone. Element 0 is for its laser, 1 is for its destruction." + /// + [Tooltip("AudioClips to play for the Drone. Element 0 is for its laser, 1 is for its destruction.")] public AudioClip[] clips; - private float _laserShotTimer; //Counting down time before shooting. - private Transform _target; // What we are looking/shooting at. - private Vector3 _gunTarget; // The Gun's target to rotate towards - private AudioSource _audioSource; //Reference to the audioSource - private Camera _leftCamera; // The ZED camera - private Renderer _renderer; // The Mesh Renderer of the Drone, so we can modify it's material - private Transform _damageFX; // FX for when we take damage - private Transform _laserAnchor; // Where we shoot the laser from. - private ParticleSystem _muzzleFlashFx; // FX for when we shoot - private Transform _droneArm; // The bone that moves the Drone's Gun. - private Vector3 _nextPosition; // The next position that the drone need to move to. - private Vector3 _velocity = Vector3.zero; // A reference for the SmoothDamp of the drone's movement. - private Light _gunLight; //The light to be enabled then disabled when the Drone has fired. - private bool canRotate = false; // Can we rotate towards our Target. - private bool canChangeLocation = false; // Are we moving the drone or not. - private DroneSpawner mySpawner; // Link with the object that spawned us. + /// + /// Counts down the time between shots. + /// + private float lasershottimer; + + /// + /// What the drone is looking/shooting at. + /// + private Transform target; + + /// + /// The gun's target to rotate towards. + /// + private Vector3 guntarget; + + /// + /// Reference to the audio source. + /// + private AudioSource audiosource; + + /// + /// The ZED camera reference, used for calling ZEDSupportFunctions as part of spawning. + /// + private Camera leftcamera; + + /// + /// The Mesh Renderer of the drone, so we can modify its material when it takes damage. + /// + private Renderer meshrenderer; + + /// + /// FX for when we take damage. + /// + private Transform damagefx; + + /// + /// Where we shoot the laser from. + /// + private Transform laseranchor; + + /// + /// FX for when we shoot. + /// + private ParticleSystem muzzleflashfx; + + /// + /// The bone that moves the drone's gun. + /// + private Transform dronearm; + + /// + /// The next position that the drone needs to move to. Set only after a valid move location has been confirmed. + /// + private Vector3 nextposition; + + /// + /// A reference for the SmoothDamp of the drone's movement. + /// + private Vector3 velocity = Vector3.zero; + + /// + /// The light to be enabled briefly when the drone has fired. + /// + private Light gunlight; + + /// + /// Whether or not we can rotate towards our target. + /// + private bool canrotate = false; + + /// + /// Are we moving the drone or not. + /// + private bool canchangerotation = false; + + /// + /// Link with the object that spawned this instance. Used to clear the spawner's reference in OnDestroy(). + /// + private DroneSpawner spawner; // Use this for initialization void Start () { //Cache the ZED's left camera for occlusion testing purposes - _leftCamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); + leftcamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); // Set the default position of the Drone to the one he spawned at. - _nextPosition = transform.position; + nextposition = transform.position; //Set the countdown timer to fire a laser - _laserShotTimer = SecondsBetweenLaserShots; + lasershottimer = SecondsBetweenLaserShots; // Set the audio source. - _audioSource = GetComponent(); - if(_audioSource != null && clips.Length > 2) + audiosource = GetComponent(); + if(audiosource != null && clips.Length > 2) { - _audioSource.clip = clips[2]; - _audioSource.volume = 1f; - _audioSource.Play(); + audiosource.clip = clips[2]; + audiosource.volume = 1f; + audiosource.Play(); } // If these variables aren't set, look for their objects by their default name. Transform[] children = transform.GetComponentsInChildren(); foreach (var child in children) { if (child.name == "Drone_Mesh") - _renderer = child.GetComponent(); + meshrenderer = child.GetComponent(); else if (child.name == "MuzzleFlash_FX") - _muzzleFlashFx = child.GetComponent(); + muzzleflashfx = child.GetComponent(); else if (child.name == "Damage_FX") - _damageFX = child; + damagefx = child; else if (child.name == "Laser_Anchor") - _laserAnchor = child; + laseranchor = child; else if (child.name == "Gun_Arm") - _droneArm = child; + dronearm = child; else if (child.name == "Point_Light") - _gunLight = child.GetComponent(); + gunlight = child.GetComponent(); } - //If the Target isn't set, set it to the PlayerDamageReceiver, assuming there is one in the scene. - if(!_target) + //If the _target isn't set, set it to the PlayerDamageReceiver, assuming there is one in the scene. + if(!target) { - _target = FindObjectOfType().transform; - _gunTarget = _target.position; + target = FindObjectOfType().transform; + guntarget = target.position; } } void Update () { //If we've flashed the damage material, lower the blend amount. - if (_renderer.material.GetFloat("_Blend") > 0) + if (meshrenderer.material.GetFloat("_Blend") > 0) { - float tmp = _renderer.material.GetFloat("_Blend"); + float tmp = meshrenderer.material.GetFloat("_Blend"); tmp -= Time.deltaTime / 1.5f; if (tmp < 0) tmp = 0; - _renderer.material.SetFloat("_Blend", tmp); + meshrenderer.material.SetFloat("_Blend", tmp); } //Enabling damage FX based on HitPoints left. switch (Hitpoints) { case 80: - _damageFX.GetChild (0).gameObject.SetActive (true); + damagefx.GetChild (0).gameObject.SetActive (true); break; case 50: - _damageFX.GetChild (1).gameObject.SetActive (true); + damagefx.GetChild (1).gameObject.SetActive (true); break; case 20: - _damageFX.GetChild (2).gameObject.SetActive (true); + damagefx.GetChild (2).gameObject.SetActive (true); break; } - //If we can change our position... - if (canChangeLocation) + //If its time to can change our position... + if (canchangerotation) { - //...then look for a new one until its a positive location. - if (FindNewMovePosition (out _nextPosition)) + //...then look for a new one until it's a valid location. + if (FindNewMovePosition (out nextposition)) { - canChangeLocation = false; + canchangerotation = false; } } //Count down the laser shot timer. If zero, fire and reset it. - _laserShotTimer -= Time.deltaTime; - if (_laserShotTimer <= 0f && _target != null) + lasershottimer -= Time.deltaTime; + if (lasershottimer <= 0f && target != null) { //Apply a degree of accuracy based on the drone distance from the player //Take a random point on a radius around the Target's position. That radius becomes smaller as the target is closer to us. - Vector3 randompoint = UnityEngine.Random.onUnitSphere * (laserAccuracy * (Vector3.Distance(_target.position, transform.position) / (mySpawner.maxSpawnDistance / 2))) + _target.position; + Vector3 randompoint = UnityEngine.Random.onUnitSphere * (laserAccuracy * (Vector3.Distance(target.position, transform.position) / (spawner.maxSpawnDistance / 2))) + target.position; //Check if the chosen point is closer to the edge of the camera. We dont want any projectile coming straight in the players eyes. - if (randompoint.z >= _target.position.z + 0.15f || randompoint.z <= _target.position.z - 0.15f) + if (randompoint.z >= target.position.z + 0.15f || randompoint.z <= target.position.z - 0.15f) { - _gunTarget = randompoint; + guntarget = randompoint; //Firing the laser FireLaser(randompoint); //Reseting the timer. - _laserShotTimer = SecondsBetweenLaserShots; + lasershottimer = SecondsBetweenLaserShots; } } //Drone Movement & Rotation - if (_target != null) { + if (target != null) + { //Get the direction to the target. - Vector3 targetDir = _target.position - transform.position; + Vector3 targetDir = target.position - transform.position; //Get the angle between the drone and the target. float angle = Vector3.Angle(targetDir, transform.forward); //Turn the drone to face the target if the angle between them if greater than... - if (angle > angleBeforeRotate && canRotate == false) { - canRotate = true; + if (angle > angleBeforeRotate && canrotate == false) + { + canrotate = true; } - if (canRotate == true) { - var newRot = Quaternion.LookRotation (_target.transform.position - transform.position); + if (canrotate == true) { + var newRot = Quaternion.LookRotation (target.transform.position - transform.position); transform.rotation = Quaternion.Lerp (transform.rotation, newRot, Time.deltaTime * 2f); - if (angle < 5 && canRotate == true) + if (angle < 5 && canrotate == true) { - canRotate = false; + canrotate = false; } } //Rotate the drone's gun to always face the target. - _droneArm.rotation = Quaternion.LookRotation (_gunTarget - _droneArm.position); + dronearm.rotation = Quaternion.LookRotation (guntarget - dronearm.position); } - //Simply moving _nextPosition to something other than transform.position will cause it to move. - if (transform.position != _nextPosition) + //Simply moving nextposition to something other than transform.position will cause it to move. + if (transform.position != nextposition) { - transform.position = Vector3.SmoothDamp(transform.position, _nextPosition,ref _velocity, smoothTime); + transform.position = Vector3.SmoothDamp(transform.position, nextposition, ref velocity, smoothTime); } } @@ -183,23 +297,23 @@ void Update () /// private void FireLaser(Vector3 randompoint) { - if (_audioSource.clip != clips[0]) + if (audiosource.clip != clips[0]) { - _audioSource.clip = clips[0]; - _audioSource.volume = 0.2f; + audiosource.clip = clips[0]; + audiosource.volume = 0.2f; } //Creat a laser object GameObject laser = Instantiate(LaserPrefab); - laser.transform.position = _laserAnchor.transform.position; - laser.transform.rotation = Quaternion.LookRotation(randompoint - _laserAnchor.transform.position); + laser.transform.position = laseranchor.transform.position; + laser.transform.rotation = Quaternion.LookRotation(randompoint - laseranchor.transform.position); //Play the Particle effect. - _muzzleFlashFx.Play(); + muzzleflashfx.Play(); //Play a sound - if (_audioSource) + if (audiosource) { - _audioSource.Play(); + audiosource.Play(); } //MuzzleFlashLight StartCoroutine(FireLight()); @@ -207,16 +321,22 @@ private void FireLaser(Vector3 randompoint) StartCoroutine(RelocationDelay()); } + /// + /// Forces a delay before moving, and then only allows rotation if the drone has reached its destination. + /// + /// IEnumerator RelocationDelay() { yield return new WaitForSeconds(1f); - //Allow to relocate if we already reached the current nextPos - if (Vector3.Distance(transform.position, _nextPosition) <= 0.1f) - canChangeLocation = true; + //Allow another relocation if we have already reached the current nextposition. + if (Vector3.Distance(transform.position, nextposition) <= 0.1f) + { + canchangerotation = true; + } } /// - /// Takes the damage. + /// What happens when the drone gets damaged. In the ZED drone demo, Lasershot_Player calls this. /// /// Damage. void ILaserable.TakeDamage(int damage) @@ -225,26 +345,26 @@ void ILaserable.TakeDamage(int damage) Hitpoints -= damage; //Blend the materials to make it take damage - _renderer.material.SetFloat("_Blend", 1); + meshrenderer.material.SetFloat("_Blend", 1); //Destroy if it's health is below zero if (Hitpoints <= 0) { //Add time to prevent laser firing while we die. - _laserShotTimer = 99f; + lasershottimer = 99f; - if(mySpawner) mySpawner.ClearDrone(); + if(spawner) spawner.ClearDrone(); if (ExplosionPrefab) { Instantiate(ExplosionPrefab, transform.position, Quaternion.identity); } - if (_audioSource != null && clips.Length > 1) + if (audiosource != null && clips.Length > 1) { - _audioSource.Stop(); - _audioSource.clip = clips[1]; - _audioSource.volume = 1f; - _audioSource.Play(); + audiosource.Stop(); + audiosource.clip = clips[1]; + audiosource.volume = 1f; + audiosource.Play(); } StartCoroutine(DestroyDrone()); @@ -252,6 +372,10 @@ void ILaserable.TakeDamage(int damage) } } + /// + /// Plays explosion FX, then destroys the drone. + /// + /// IEnumerator DestroyDrone() { transform.GetChild(0).gameObject.SetActive(false); @@ -260,6 +384,13 @@ IEnumerator DestroyDrone() Destroy(gameObject); } + /// + /// Checks nearby for valid places for the drone to move. + /// Valid places must be in front of the player, and not intersect any objects within a reasonable tolerance. + /// Use radiusCheckRate and percentageThreshold to tweak what counts as a valid location. + /// + /// + /// private bool FindNewMovePosition(out Vector3 newpos) { //We can't move if the ZED isn't initialized. @@ -272,13 +403,13 @@ private bool FindNewMovePosition(out Vector3 newpos) Vector3 randomPosition; // Look Around For a New Position //If the Drone is on the screen, search around a smaller radius. - if (ZEDSupportFunctions.CheckScreenView(transform.position, _leftCamera)) + if (ZEDSupportFunctions.CheckScreenView(transform.position, leftcamera)) randomPosition = UnityEngine.Random.onUnitSphere * UnityEngine.Random.Range(2f, 3f) + transform.position; else //if the drone is outside, look around a bigger radius to find a position which is inside the screen. randomPosition = UnityEngine.Random.onUnitSphere * UnityEngine.Random.Range(4f, 5f) + transform.position; // Look For Any Collisions Through The ZED - bool hit = ZEDSupportFunctions.HitTestAtPoint(_leftCamera, randomPosition); + bool hit = ZEDSupportFunctions.HitTestAtPoint(leftcamera, randomPosition); if (!hit) { @@ -287,11 +418,11 @@ private bool FindNewMovePosition(out Vector3 newpos) } //If we spawn the drone at that world point, it'll spawn inside a wall. Bring it closer by a distance of ClearRadius. - Quaternion directiontoDrone = Quaternion.LookRotation(_leftCamera.transform.position - randomPosition, Vector3.up); + Quaternion directiontoDrone = Quaternion.LookRotation(leftcamera.transform.position - randomPosition, Vector3.up); Vector3 newPosition = randomPosition + directiontoDrone * Vector3.forward * ClearRadius; //Check the new position isn't too close from the camera. - float dist = Vector3.Distance(_leftCamera.transform.position, randomPosition); + float dist = Vector3.Distance(leftcamera.transform.position, randomPosition); if (dist < 1f) { newpos = transform.position; @@ -299,7 +430,7 @@ private bool FindNewMovePosition(out Vector3 newpos) } //Also check nearby points in a sphere of radius to make sure the whole drone has a clear space. - if (ZEDSupportFunctions.HitTestOnSphere(_leftCamera, newPosition, 1f, radiusCheckRate, percentageThreshold)) + if (ZEDSupportFunctions.HitTestOnSphere(leftcamera, newPosition, 1f, radiusCheckRate, percentageThreshold)) { newpos = transform.position; return false; @@ -310,15 +441,24 @@ private bool FindNewMovePosition(out Vector3 newpos) return true; } + /// + /// Sets a reference to the Drone spawner governing its spawning. + /// Used to notify the spawner when it's destroyed. + /// + /// Reference to the scene's DroneSpawner component. public void SetMySpawner(DroneSpawner spawner) { - mySpawner = spawner; + this.spawner = spawner; } + /// + /// Turns on the drone gun's light briefly to simulate a muzzle flash. Because lasers totally have muzzle flashes. + /// + /// IEnumerator FireLight() { - _gunLight.enabled = true; + gunlight.enabled = true; yield return new WaitForSeconds(0.15f); - _gunLight.enabled = false; + gunlight.enabled = false; } } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/DroneSpawner.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/DroneSpawner.cs index aed92ac8..608f3820 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/DroneSpawner.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/DroneSpawner.cs @@ -3,35 +3,95 @@ using UnityEngine; using UnityEngine.UI; +/// +/// Spawns a given Drone prefab when there is not one already in the scene. +/// It will only spawn drones in front of the user and when it can find a location where it wouldn't intersect the real world. +/// It will also not spawn drones if one already exists, or if _canSpawn is set to false, which is the case on start until the warning message finishes displaying). +/// Used in the ZED Drone Battle example scene. +/// public class DroneSpawner : MonoBehaviour { + /// + /// The Drone prefab to spawn. + /// [Tooltip("The Drone prefab to spawn.")] public GameObject dronePrefab; - [Tooltip("The warning message to spawn.")] + + /// + /// The warning message to spawn at the start of the scene. Text is set by WarningDisplay() but the prefab holds the UI elements. + /// + [Tooltip("The warning message to spawn at the start of the scene. Text is set by WarningDisplay() but the prefab holds the UI elements.")] public GameObject spawnWarning; + + /// + /// How far a point must be from real geometry to be considered a valid spawn location. + /// [Tooltip("How far a point must be from real geometry to be considered a valid spawn location.")] public float clearRadius = 1f; - [Tooltip("How many times should we look around our chosen spawnPoint to see if there are any obstacles around it.")] - public int radiusCheckRate = 200; - [Tooltip("The maximum amount of collisions detected near a spawn point allowed.")] + + /// + /// How many times should we check near a potential spawn point to see if there are any obstacles around it. + /// Higher numbers reduce the chance of spawning partially inside an object but may cause stutters. + /// + [Tooltip("How many times should we check near a potential spawn point to see if there are any obstacles around it. " + + "Higher numbers reduce the chance of spawning partially inside an object but may cause stutters.")] + public int radiusCheckRate = 200; + + /// + /// The maximum number of collisions detected near a spawn point allowed. Higher values make it less likely for a drone to move inside an object, but too high and it may not move at all. + /// + [Tooltip("The maximum number of collisions detected near a spawn point allowed. " + + "Higher values make it less likely for a drone to spawn inside an object, but too high and it may not spawn at all.")] public float percentagethreshold = 0.4f; - [Tooltip("How long we wait after a drone's death before spawning a new one")] + + /// + /// How long we wait (in seconds) after a drone's death before spawning a new one. + /// + [Tooltip("How long we wait (in seconds) after a drone's death before spawning a new one.")] public float respawnTimer = 2f; - [Tooltip("What is the maximum distance the drone can be spawned.")] + + /// + /// The maximum distance from a player that a drone can be spawned. + /// + [Tooltip("The maximum distance from a player that a drone can be spawned.")] public float maxSpawnDistance = 6f; - private Vector3 _randomPosition; //The random position to be used when spawning a new drone. - private float _respawnCountdown; //Time counting down before spawning a new dorne. - private Drone _currentDrone; //The last spawned drone that is still active. - private Camera _leftCamera; //Needed for depth calculation - private bool _warning; //Did we display the warning message before spawning the Drones. - private bool _canSpawn; //Last check before starting spawning to allow warning message being displayed. + /// + /// The random position to be used when spawning a new drone. + /// Assigned only once a valid position has been found. + /// + private Vector3 newspawnposition; + + /// + /// Time counting down before spawning a new drone. + /// + private float respawncountdown; + + /// + /// The last spawned drone that is still active. + /// + private Drone currentdrone; + + /// + /// Needed for various calls to ZEDSupportFunctions.cs, so it can transform ZED depth info into world space. + /// + private Camera leftcamera; + + /// + /// Whether we already displayed the warning message before spawning the drones. + /// + private bool displayedwarning; + + /// + /// Last check before starting to spawn drones, to allow warning message to be displayed. + /// + private bool canspawn; private bool _readyToSpawn { get { - if (_currentDrone == null && _respawnCountdown <= 0) return true; + if (currentdrone == null && respawncountdown <= 0) return true; else return false; } } @@ -40,73 +100,73 @@ private bool _readyToSpawn void Start() { //Set the countdown Timer; - _respawnCountdown = respawnTimer; + respawncountdown = respawnTimer; //Get the ZED camera - _leftCamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); + leftcamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); } // Update is called once per frame void Update() { //Reposition the screen in front our the Camera when its ready - if (ZEDManager.Instance.IsZEDReady && !_warning) + if (ZEDManager.Instance.IsZEDReady && !displayedwarning) { StartCoroutine(WarningDisplay()); - _warning = true; + displayedwarning = true; } - if (!_canSpawn) + if (!canspawn) return; //Tick down the respawn timer if applicable - if (_respawnCountdown > 0) + if (respawncountdown > 0) { - _respawnCountdown -= Time.deltaTime; + respawncountdown -= Time.deltaTime; } if (_readyToSpawn) //We've got no drone and the respawn timer has elapsed { - //Try to spawn a drone in a random place in front of the player. We'll do once per frame for now. - if (CheckRandomSpawnLocation(out _randomPosition)) + //Try to spawn a drone in a random place in front of the player. We'll do this only once per frame to avoid stuttering. + if (CheckRandomSpawnLocation(out newspawnposition)) { - _currentDrone = SpawnDrone(_randomPosition); + currentdrone = SpawnDrone(newspawnposition); } } - //Debug Solution to spawn drone multiple times for testing. - //On Input Down, destroy current drone. - if (Input.GetKeyDown (KeyCode.Mouse1)) { - //Destroys the current Drone. - Destroy(_currentDrone.gameObject); - ClearDrone (); - } } Text msg; - IEnumerator WarningDisplay() + /// + /// Positions, configures and displays the warning text at the start of the game. + /// Sets canspawn (which defaults to false) to true once finished, so that drones only spawn afterward. + /// + /// + IEnumerator WarningDisplay() { - GameObject warningMsg = Instantiate(spawnWarning); + GameObject warningMsg = Instantiate(spawnWarning); //Spawn the message prefab, which doesn't have the correct text yet. warningMsg.transform.position = ZEDManager.Instance.OriginPosition + ZEDManager.Instance.OriginRotation * (Vector3.forward*2); Quaternion newRot = Quaternion.LookRotation(ZEDManager.Instance.OriginPosition - warningMsg.transform.position, Vector3.up); warningMsg.transform.eulerAngles = new Vector3(0, newRot.eulerAngles.y + 180, 0); - Text msg = warningMsg.GetComponentInChildren(); + Text msg = warningMsg.GetComponentInChildren(); //Find the text in the prefab. yield return new WaitForSeconds(1f); + //Add the letters to the message one at a time for effect. int i = 0; string oldText = "WARNING! DEPLOYING DRONES!"; string newText = ""; - while (i < oldText.Length) + while (i < oldText.Length) { newText += oldText[i++]; - yield return new WaitForSeconds(0.15F); + yield return new WaitForSeconds(0.15F); msg.text = newText; } - yield return new WaitForSeconds(3f); + yield return new WaitForSeconds(3f); //Let the user read it for a few seconds. + //Change the warning message by clearing it and adding letters one at a time like before. i = 0; oldText = "DEFEND YOURSELF!"; newText = ""; @@ -117,13 +177,14 @@ IEnumerator WarningDisplay() msg.text = newText; } - yield return new WaitForSeconds(3f); + yield return new WaitForSeconds(3f);//Let the user read it for a few seconds. + Destroy(warningMsg); - _canSpawn = true; + canspawn = true; //Drones can now spawn. } /// - /// looks for a random point in a radius around itself. + /// Looks for a random point in a radius around itself. /// Upon collision, the point is moved slightly towards the camera and if its too far it's set to "maxSpawnDistance". /// A more thorough search is then done for any other obstacles around it, also, in a radius. /// If the number of collision doesn't exeeds the set threshold, then return true and output the new position. @@ -144,7 +205,7 @@ private bool CheckRandomSpawnLocation(out Vector3 newRandomPos) //Get the world position of that position in the real world Vector3 randomWorldPoint; - bool foundWorldPoint = ZEDSupportFunctions.GetWorldPositionAtPixel(randomScreenPoint, _leftCamera, out randomWorldPoint); + bool foundWorldPoint = ZEDSupportFunctions.GetWorldPositionAtPixel(randomScreenPoint, leftcamera, out randomWorldPoint); if (!foundWorldPoint) //We can't read depth from that point. { @@ -152,7 +213,7 @@ private bool CheckRandomSpawnLocation(out Vector3 newRandomPos) return false; } - float firstDistance = Vector3.Distance (_leftCamera.transform.position, randomWorldPoint); + float firstDistance = Vector3.Distance (leftcamera.transform.position, randomWorldPoint); float newClearRadius; //Check that the distance isn't too far. @@ -162,11 +223,11 @@ private bool CheckRandomSpawnLocation(out Vector3 newRandomPos) newClearRadius = clearRadius; //If we spawn the drone at that world point, it'll spawn inside a wall. Bring it between you and that wall. - Quaternion directionToCamera = Quaternion.LookRotation(_leftCamera.transform.position - randomWorldPoint, Vector3.up); + Quaternion directionToCamera = Quaternion.LookRotation(leftcamera.transform.position - randomWorldPoint, Vector3.up); Vector3 closerWorldPoint = randomWorldPoint + directionToCamera * Vector3.forward * newClearRadius; //Check that distance isn't too close - float secondDistance = Vector3.Distance(_leftCamera.transform.position, closerWorldPoint); + float secondDistance = Vector3.Distance(leftcamera.transform.position, closerWorldPoint); if (secondDistance < 1f) { newRandomPos = Vector3.zero; @@ -174,7 +235,7 @@ private bool CheckRandomSpawnLocation(out Vector3 newRandomPos) } //Also check nearby points in a sphere of radius=ClearRadius to make sure the whole drone has a clear space. - if (ZEDSupportFunctions.HitTestOnSphere(_leftCamera, closerWorldPoint, 1f, radiusCheckRate, percentagethreshold)) + if (ZEDSupportFunctions.HitTestOnSphere(leftcamera, closerWorldPoint, 1f, radiusCheckRate, percentagethreshold)) { //Not clear. newRandomPos = Vector3.zero; @@ -201,24 +262,28 @@ public Drone SpawnDrone(Vector3 spawnPosition) if (!dronecomponent) { - Debug.Log("Drone prefab spawned by DroneSpawner does not contain the Drone.cs component."); + Debug.LogError("Drone prefab spawned by DroneSpawner does not contain the Drone.cs component."); } //Give the drone a reference to this object so it can clear its reference and set the timer properly when it dies dronecomponent.SetMySpawner(this); //Set the drone's transform values - dronego.transform.position = _randomPosition; //Assign the random Pos generated in CheckRandomSpawnLocation(); + dronego.transform.position = newspawnposition; //Assign the random Pos generated in CheckRandomSpawnLocation(); dronego.transform.rotation = Quaternion.LookRotation(ZEDManager.Instance.GetLeftCameraTransform().position - spawnPosition, Vector3.up); //Make it look at the player. return dronecomponent; } - public void ClearDrone() //To be called by a drone when it dies. + /// + /// Clears the drone reference, which will cause the script to start trying to spawn a new one again. + /// Should be called by the drone itself in its OnDestroy(). + /// + public void ClearDrone() { - _currentDrone = null; - _respawnCountdown = respawnTimer; + currentdrone = null; + respawncountdown = respawnTimer; print("Drone destroyed"); } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserGun.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserGun.cs index 7118a48d..e7700137 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserGun.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserGun.cs @@ -2,22 +2,52 @@ using System.Collections.Generic; using UnityEngine; +/// +/// Fires a laser when the user issues a command. +/// If there is a ZEDControllerTracker in the same object, and the Oculus Integration or SteamVR plugins are installed, +/// it'll automatically check them for inputs. +/// [RequireComponent(typeof(AudioSource))] public class LaserGun : MonoBehaviour { - [Tooltip("What we spawn when the trigger is pulled")] - public GameObject LaserShotPrefab; - [Tooltip("Anchor object of the PointerBead")] - public GameObject LaserPointerBeadHolder; - [Tooltip("Anchor point to spawn the Laser.")] - public Transform LaserSpawnLocation; - - private GameObject PointerBead; //Reference to the object that will be placed at the end of the laser. - private AudioSource _audioSource; //Reference to the audioSource - private Camera LeftCamera; //Reference to the ZED's left camera gameobject. - - //The gameobject's controller for tracking & input. - private ZEDControllerTracker objectTracker; + /// + /// What we spawn when the trigger is pulled. + /// + [Tooltip("What we spawn when the trigger is pulled.")] + public GameObject laserShotPrefab; + + /// + /// Anchor object of the PointerBead, which works as a crosshair. + /// + [Tooltip("Anchor object of the PointerBead, which works as a crosshair.")] + public GameObject laserPointerBeadHolder; + + /// + /// Anchor point where the laser spawns. + /// + [Tooltip("Anchor point where the laser spawns.")] + public Transform laserSpawnLocation; + + /// + /// Reference to the object that will be placed at the end of the laser. + /// + private GameObject pointerbead; + + /// + /// Reference to the audio source + /// + private AudioSource audiosource; + + /// + /// Reference to the ZED's left camera gameobject. Used to pass to ZEDSupportFunctions.cs so it can transform ZED depth info into world space. + /// + private Camera leftcamera; + + /// + /// The gameobject's controller for tracking and input. + /// + private ZEDControllerTracker objecttracker; + #if ZED_OCULUS private int fireCount = 0; #endif @@ -25,31 +55,31 @@ public class LaserGun : MonoBehaviour IEnumerator Start() { //Find the left camera object if we didn't assign it at start. - if (!LeftCamera) + if (!leftcamera) { - LeftCamera = ZEDManager.Instance.GetLeftCameraTransform().gameObject.GetComponent(); + leftcamera = ZEDManager.Instance.GetLeftCameraTransform().gameObject.GetComponent(); } - _audioSource = GetComponent(); + audiosource = GetComponent(); - if (LaserPointerBeadHolder != null) + if (laserPointerBeadHolder != null) { //Get the laser bead from the parent/achor object. - PointerBead = LaserPointerBeadHolder.transform.GetChild(0).gameObject; + pointerbead = laserPointerBeadHolder.transform.GetChild(0).gameObject; //Disable the laser bead to wait for the ZED to initialize. - PointerBead.SetActive(false); + pointerbead.SetActive(false); } //Wait for VR Controllers to initilize yield return new WaitForSeconds(1f); - objectTracker = GetComponent(); + objecttracker = GetComponent(); - if (objectTracker != null) + if (objecttracker != null) { #if ZED_STEAM_VR - if (objectTracker.index >= 0) + if (objecttracker.index >= 0) yield break; #endif #if ZED_OCULUS @@ -104,7 +134,7 @@ IEnumerator Start() void Update () { //Do we have a Pointer Bead to position in the world? - if (LaserPointerBeadHolder != null) + if (laserPointerBeadHolder != null) { Vector3 crosshairpoint; Vector3 crosshairnormal; @@ -112,17 +142,17 @@ void Update () if (ZEDManager.Instance.IsZEDReady && FindCrosshairPosition(out crosshairpoint, out crosshairnormal)) { //We hit something. Make sure the bead is active. - PointerBead.SetActive(true); + pointerbead.SetActive(true); //Position the bead a the collision point, and make it face you. - PointerBead.transform.position = crosshairpoint; + pointerbead.transform.position = crosshairpoint; if(crosshairnormal.magnitude > 0.0001f) - PointerBead.transform.rotation = Quaternion.LookRotation(crosshairnormal); + pointerbead.transform.rotation = Quaternion.LookRotation(crosshairnormal); } else { //We didn't hit anything. Disable the bead object. - PointerBead.SetActive(false); + pointerbead.SetActive(false); } } @@ -141,11 +171,11 @@ void Update () //We're controlling the fire Rate OVRInput doesn't have a GetDown function for the IndexTrigger. Only an axis output. - if (objectTracker != null) + if (objecttracker != null) { if (OVRInput.GetConnectedControllers().ToString() == "Touch") { - if ((int)objectTracker.deviceToTrack == 0) + if ((int)objecttracker.deviceToTrack == 0) { if (fireCount == 0 && OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.RTouch) > 0.75f) { @@ -156,7 +186,7 @@ void Update () fireCount = 0; } - if ((int)objectTracker.deviceToTrack == 1) + if ((int)objecttracker.deviceToTrack == 1) { if (fireCount == 0 && OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.LTouch) > 0.75f) { @@ -172,15 +202,15 @@ void Update () #endif #if ZED_STEAM_VR //Looks for any input from this controller through SteamVR - if (objectTracker != null) + if (objecttracker != null) { - if ((int)objectTracker.deviceToTrack == 0 && objectTracker.index >= 0) - if (SteamVR_Controller.Input((int)objectTracker.index).GetHairTriggerDown()) + if ((int)objecttracker.deviceToTrack == 0 && objecttracker.index >= 0) + if (SteamVR_Controller.Input((int)objecttracker.index).GetHairTriggerDown()) { buttondown = true; } - if ((int)objectTracker.deviceToTrack == 1 && objectTracker.index >= 0) - if (SteamVR_Controller.Input((int)objectTracker.index).GetHairTriggerDown()) + if ((int)objecttracker.deviceToTrack == 1 && objecttracker.index >= 0) + if (SteamVR_Controller.Input((int)objecttracker.index).GetHairTriggerDown()) { buttondown = true; } @@ -193,18 +223,22 @@ void Update () } } - bool FindCrosshairPosition(out Vector3 crosshairpoint, out Vector3 collisionnormal) + /// + /// Tests the depth of both the real and virtual in the center of the screen, and returns the world position of the closest one. + /// + /// Where the crosshair should be rendered. + /// The normal vector of the surface aimed at, for rotating the crosshair accordingly if desired. + /// False if there is no valid object, real or virtual, on which to place the crosshair. + private bool FindCrosshairPosition(out Vector3 crosshairpoint, out Vector3 collisionnormal) { - //Tests the depth of both the real and virtual in the center of the screen, and returns the world position of the closest one. - //Find the distance to the real world. The bool will be false if there is an error reading the depth at the center of the screen. Vector3 realpoint; - bool foundrealdistance = ZEDSupportFunctions.HitTestOnRay(LeftCamera, LaserPointerBeadHolder.transform.position, LaserPointerBeadHolder.transform.rotation, 5f, 0.01f, out realpoint); - float realdistance = Vector3.Distance(LaserPointerBeadHolder.transform.position, realpoint); + bool foundrealdistance = ZEDSupportFunctions.HitTestOnRay(leftcamera, laserPointerBeadHolder.transform.position, laserPointerBeadHolder.transform.rotation, 5f, 0.01f, out realpoint); + float realdistance = Vector3.Distance(laserPointerBeadHolder.transform.position, realpoint); //Find the distance to the virtual. The bool will be false if there are no colliders ahead of you. RaycastHit hitinfo; - bool foundvirtualdistance = Physics.Raycast(LaserPointerBeadHolder.transform.position, LaserPointerBeadHolder.transform.rotation * Vector3.forward, out hitinfo); + bool foundvirtualdistance = Physics.Raycast(laserPointerBeadHolder.transform.position, laserPointerBeadHolder.transform.rotation * Vector3.forward, out hitinfo); //If we didn't find either, return false so the laser and bead can be disabled. if (!foundrealdistance && !foundvirtualdistance) @@ -219,7 +253,7 @@ bool FindCrosshairPosition(out Vector3 crosshairpoint, out Vector3 collisionnorm { //The real world is closer. Give the position of the real world pixel and return true. crosshairpoint = realpoint; - ZEDSupportFunctions.GetNormalAtWorldLocation(realpoint, sl.REFERENCE_FRAME.WORLD, LeftCamera, out collisionnormal); + ZEDSupportFunctions.GetNormalAtWorldLocation(realpoint, sl.REFERENCE_FRAME.WORLD, leftcamera, out collisionnormal); return true; } else @@ -232,19 +266,22 @@ bool FindCrosshairPosition(out Vector3 crosshairpoint, out Vector3 collisionnorm } + /// + /// Spawns the laser prefab at the spawn anchor. + /// void Fire() { //Create the shot and position/rotate it accordingly. - GameObject blastershot = Instantiate(LaserShotPrefab); - blastershot.transform.position = LaserSpawnLocation != null ? LaserSpawnLocation.transform.position : transform.position; - blastershot.transform.rotation = LaserSpawnLocation != null ? LaserSpawnLocation.transform.rotation : transform.rotation; - if (LaserPointerBeadHolder != null) - blastershot.transform.LookAt(PointerBead.transform.position); + GameObject blastershot = Instantiate(laserShotPrefab); + blastershot.transform.position = laserSpawnLocation != null ? laserSpawnLocation.transform.position : transform.position; + blastershot.transform.rotation = laserSpawnLocation != null ? laserSpawnLocation.transform.rotation : transform.rotation; + if (laserPointerBeadHolder != null) + blastershot.transform.LookAt(pointerbead.transform.position); //Play a sound - if (_audioSource) + if (audiosource) { - _audioSource.Play(); + audiosource.Play(); } } } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Drone.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Drone.cs index 4b67dcfc..0f44fc1a 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Drone.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Drone.cs @@ -4,28 +4,48 @@ /// /// A Projectile that spawns an explosion effect on death and causes the player to see a damage effect when hit. +/// Inherits from Projectile.cs, where most logic not specific to the ZED Drone Battle sample is handled. /// -public class LaserShot_Drone : Projectile +public class LaserShot_Drone : ZEDProjectile { - [Tooltip("Explosion object to spawn on death")] - public GameObject ExplosionPrefab; - private float camDistance; + /// + /// Explosion object to spawn on death. + /// + [Tooltip("Explosion object to spawn on death.")] + public GameObject explosionPrefab; + + /// + /// The current distance the object is from the left eye camera, used for collision calculation. + /// + private float camdistance; private void Update() { - camDistance = Vector3.Distance(transform.position, _leftCamera.transform.position); - if (camDistance < 1.5f) - Speed = 1f; + camdistance = Vector3.Distance(transform.position, leftcamera.transform.position); + if (camdistance < 1.5f) + speed = 1f; else - Speed = 16f; + speed = 16f; } + /// + /// Called when the projectile hits the real world. + /// As the real world can't be a distinct gameobject (for now) we just spawn FX and destroy the projectile. + /// + /// + /// public override void OnHitRealWorld(Vector3 collisionpoint, Vector3 collisionnormal) { SpawnExplosion(collisionpoint, collisionnormal); Destroy(gameObject); } + /// + /// Called when the projectile hits a virtual object. + /// If that object has a PlayerDamageReceiver, deal damage and destroy the projectile. + /// Otherwise ignore it so the drone can't shoot itself. + /// + /// public override void OnHitVirtualWorld(RaycastHit hitinfo) { //Check to see if it's the player we hit. If so, deal damage. @@ -38,11 +58,16 @@ public override void OnHitVirtualWorld(RaycastHit hitinfo) } } + /// + /// Creates an explosion effect at the desired location, used when the laser is destroyed. + /// + /// Where to spawn the explosion. + /// Which direction to orient the explosion. Should be based off the surface normal of the object the projectile hit. void SpawnExplosion(Vector3 position, Vector3 normal) { - if (ExplosionPrefab) //Only spawn an explosion if we have a prefab to spawn + if (explosionPrefab) //Only spawn an explosion if we have a prefab to spawn { - GameObject explosion = Instantiate(ExplosionPrefab); + GameObject explosion = Instantiate(explosionPrefab); explosion.transform.position = position; explosion.transform.rotation = Quaternion.LookRotation(normal); } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Player.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Player.cs index 8aba1a31..a4073766 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Player.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/LaserShot_Player.cs @@ -4,20 +4,40 @@ /// /// A Projectile that spawns an explosion effect on death and deals damage to objects with ILaserable in their root gameobject. +/// Inherits from Projectile.cs, where most logic not specific to the ZED Drone Battle sample is handled. /// -public class LaserShot_Player : Projectile +public class LaserShot_Player : ZEDProjectile { + /// + /// How much damage we do to a drone, or another object that inherits from ILaserable. + /// [Tooltip("How much damage we do to a drone, or another object that inherits from ILaserable.")] public int Damage = 10; - [Tooltip("Explosion object to spawn on death")] - public GameObject ExplosionPrefab; + /// + /// Explosion object to spawn on death. + /// + [Tooltip("Explosion object to spawn on death.")] + public GameObject explosionPrefab; + + /// + /// Called when the projectile hits the real world. + /// As the real world can't be a distinct gameobject (for now) we just spawn FX and destroy the projectile. + /// + /// + /// public override void OnHitRealWorld(Vector3 collisionpoint, Vector3 collisionnormal) { SpawnExplosion(collisionpoint, collisionnormal); Destroy(gameObject); } + /// + /// Called when the projectile hits a virtual object. + /// If the object has a component that implements ILaserable, deal damage and destroy the projectile. + /// Otherwise ignore it so the player can't shoot themselves. + /// + /// public override void OnHitVirtualWorld(RaycastHit hitinfo) { //Deal damage to an object if it contains ILaserable, such as a drone @@ -34,11 +54,16 @@ public override void OnHitVirtualWorld(RaycastHit hitinfo) } } + /// + /// Creates an explosion effect at the desired location, used when the laser is destroyed. + /// + /// Where to spawn the explosion. + /// Which direction to orient the explosion. Should be based off the surface normal of the object the projectile hit. void SpawnExplosion(Vector3 position, Vector3 normal) { - if (ExplosionPrefab) //Only spawn an explosion if we have a prefab to spawn + if (explosionPrefab) //Only spawn an explosion if we have a prefab to spawn { - GameObject explosion = Instantiate(ExplosionPrefab); + GameObject explosion = Instantiate(explosionPrefab); explosion.transform.position = position; explosion.transform.rotation = Quaternion.LookRotation(normal); } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/PlayerDamageReceiver.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/PlayerDamageReceiver.cs index 6ce8514e..9853aba1 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/PlayerDamageReceiver.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Simple/PlayerDamageReceiver.cs @@ -4,37 +4,57 @@ /// /// Handles fading in/out the material of the object it's attached to for an effect when the player takes damage. +/// in the ZED Drone Battle sample, this makes a sphere around the player's head turn red and fade out over a second. Also plays a sound. +/// Used by LaserShot_Drone to know when a laser hit the player's head, which then also calls TakeDamage() to make it happen. /// [RequireComponent(typeof(MeshRenderer))] [RequireComponent(typeof(Collider))] public class PlayerDamageReceiver : MonoBehaviour { - public float SecondsToDisplayEffect = 1f; - private MeshRenderer _renderer; - private float _maxColorAlpha; //The highest value the material will be set to + /// + /// How long to display the damage effect. + /// + [Tooltip("How long to display the damage effect. ")] + public float secondsToDisplayEffect = 1f; - private float _colorAlpha + /// + /// The highest value the damage sphere's material color will be set to + /// + private float maxcoloralpha; + + /// + /// The current alpha value of the damage sphere's material color. + /// + private float coloralpha { get { - return _renderer.material.color.a; + return meshrenderer.material.color.a; } set { - _renderer.material.color = new Color(_renderer.material.color.r, _renderer.material.color.g, _renderer.material.color.b, value); + meshrenderer.material.color = new Color(meshrenderer.material.color.r, meshrenderer.material.color.g, meshrenderer.material.color.b, value); } } + /// + /// The MeshRenderer attached to this GameObject. + /// + private MeshRenderer meshrenderer; + + /// + /// The AudioSource attached to this GameObject for playing the hurt sound. + /// private AudioSource _audioSource; // Use this for initialization void Start() { - _renderer = GetComponent(); - _maxColorAlpha = _renderer.material.color.a; + meshrenderer = GetComponent(); + maxcoloralpha = meshrenderer.material.color.a; //Set the alpha to zero as we haven't taken damage yet. - _colorAlpha = 0f; + coloralpha = 0f; _audioSource = GetComponent(); } @@ -43,19 +63,22 @@ void Start() void Update() { //Tick down the color if it's above zero. - if(_colorAlpha > 0f) + if(coloralpha > 0f) { - _colorAlpha -= Time.deltaTime / SecondsToDisplayEffect * _maxColorAlpha; + coloralpha -= Time.deltaTime / secondsToDisplayEffect * maxcoloralpha; } } + /// + /// Causes the damage effect to play once. + /// public void TakeDamage() { - _colorAlpha = _maxColorAlpha; + coloralpha = maxcoloralpha; //Set the damage sphere to as high as we want it to ever get if(_audioSource) { - _audioSource.Play(); + _audioSource.Play(); //Play the "ouch" sound. } } } \ No newline at end of file diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/DestroyAfterTime.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/DestroyAfterTime.cs index 7add006b..401a0e27 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/DestroyAfterTime.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/DestroyAfterTime.cs @@ -3,8 +3,16 @@ using UnityEngine; using UnityEngine.Networking; +/// +/// Destroys the object it's attached to after a pre-specified amount of time. Used for explosion effects. +/// Similar to Unity's Destroy(GameObject, float) overload, but allows it to be set easily in the Inspector. +/// public class DestroyAfterTime : MonoBehaviour { + /// + /// How long the gameobject exists. + /// + [Tooltip("How long the gameobject exists.")] public float DeathClock = 2f; // Update is called once per frame @@ -16,5 +24,6 @@ void Update () { Destroy(gameObject); } + } } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ILaserable.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ILaserable.cs index ab35c89d..b91ab445 100644 --- a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ILaserable.cs +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ILaserable.cs @@ -2,12 +2,15 @@ using System.Collections.Generic; using UnityEngine; +/// +/// Interface used by LaserShot_Player to deal damage. Implement in an object you want to be able to damage with the player's laser gun. +/// public interface ILaserable { /// - /// Have an object inherit this if you want it to be damageable by the LaserShot_Player script in the ZED Drone Battle sample. + /// Deal damage in some way. /// - + /// How much damage to deal. void TakeDamage(int damage); } diff --git a/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ZEDProjectile.cs b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ZEDProjectile.cs new file mode 100644 index 00000000..f2c6a262 --- /dev/null +++ b/ZEDCamera/Assets/ZED/Examples/Drone Shooter/Scripts/Utilities/ZEDProjectile.cs @@ -0,0 +1,108 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Networking; + +/// +/// Checks for collisions with both the real and virtual world and moves forward each frame. +/// Inherit from this class to easily make your own projectile that can hit both the virtual and real. +/// See LaserShot_Drone and LaserShot_Player in the ZED Drone Battle sample for examples. +/// Real world "collisions" test if it's behind the real world using the static hit test functions in ZEDSupportFunctions. +/// +public class ZEDProjectile : MonoBehaviour +{ + /// + /// How fast the projectile moves forward in meters per second. + /// + [Tooltip("How fast the projectile moves forward in meters per second.")] + public float speed = 10f; + + /// + /// How long the projectile lasts before being destroyed, even if it doesn't collide with anything. + /// + [Tooltip("How long the projectile lasts before being destroyed, even if it doesn't collide with anything.")] + public float lifespan = 8f; + + /// + /// How granular the dots are along the fake raycast done for real-world collisions. + /// + [Tooltip("How granular the dots are along the fake raycast done for real-world collisions.")] + public float distanceBetweenRayChecks = 0.01f; + + /// + /// How far behind a real pixel can a collision check decide it's not a collision. + /// + [Tooltip("How far behind a real pixel can a collision check decide it's not a collision.")] + public float realWorldThickness = 0.05f; + + /// + /// The ZED camera reference, used for calling ZEDSupportFunctions to transform depth data from the ZED into world space. + /// + protected Camera leftcamera; + + private void Awake() + { + if (!leftcamera) + { + leftcamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); + } + } + + /// + /// Handles movements and collisions on a constant basis. + /// + void FixedUpdate() + { + //Calculate where the object should move this frame + Vector3 newpos = transform.position + transform.rotation * Vector3.forward * (speed * Time.deltaTime); + + //Collisions with the real World. As the object moves, collisions checks are made each frame at the next position. + Vector3 collisionpoint; + if (ZEDSupportFunctions.HitTestOnRay(leftcamera, newpos, transform.rotation, Vector3.Distance(transform.position, newpos), distanceBetweenRayChecks, out collisionpoint, false, realWorldThickness)) + { + //Call the function to resolve the impact. This allows us to easily override what happens on collisions with classes that inherit this one. + Vector3 collisionnormal; + ZEDSupportFunctions.GetNormalAtWorldLocation(collisionpoint, sl.REFERENCE_FRAME.WORLD, leftcamera, out collisionnormal); + + OnHitRealWorld(collisionpoint, collisionnormal); + } + + //Collisions with virtual objects + //Cast a ray to check collisions between here and the intended move point for virtual objects. + RaycastHit hitinfo; + if (Physics.Raycast(transform.position, newpos - transform.position, out hitinfo, Vector3.Distance(transform.position, newpos))) + { + //Call the function to resolve the impact. This allows us to easily override what happens on collisions with classes that inherit this one. + OnHitVirtualWorld(hitinfo); + } + + //Move it to this new place + transform.position = newpos; + + //Tick down its lifespan and check if we should destroy it. + lifespan -= Time.deltaTime; + if (lifespan <= 0f) + { + Destroy(gameObject); + } + } + + /// + /// Called when the projectile hits real geometry. Override to spawn effects, play sounds, etc. + /// + /// + /// + public virtual void OnHitRealWorld(Vector3 collisionpoint, Vector3 collisionnormal) + { + Destroy(gameObject); + } + + /// + /// Called when the projectile hits a virtual collider. Override to spawn effects, inflict damage, etc. + /// + /// The RayCastHit supplied by the raycast used to detect the collision. + public virtual void OnHitVirtualWorld(RaycastHit hitinfo) + { + Destroy(gameObject); + } +} diff --git a/ZEDCamera/Assets/ZED/Examples/GreenScreen/Editor/GreenScreenEditor.cs b/ZEDCamera/Assets/ZED/Examples/GreenScreen/Editor/GreenScreenEditor.cs index 23e88317..2fd60674 100644 --- a/ZEDCamera/Assets/ZED/Examples/GreenScreen/Editor/GreenScreenEditor.cs +++ b/ZEDCamera/Assets/ZED/Examples/GreenScreen/Editor/GreenScreenEditor.cs @@ -2,6 +2,11 @@ using UnityEditor; using UnityEngine; using System.IO; + +/// +/// Custom Editor that extends the default settings shown in the Inspector. +/// Allows it to add buttons and hidden elements for the garbage matte and config file. +/// [CustomEditor(typeof(GreenScreenManager))] class GreenScreenManagerEditor : Editor { @@ -32,7 +37,7 @@ public void OnEnable() { greenScreen = (GreenScreenManager)target; - + //Create serialized properties for all the GreenScreenManager's fields so they can be modified and saved/serialized properly. keyColors = serializedObject.FindProperty("keyColors"); erosion = serializedObject.FindProperty("erosion"); @@ -55,7 +60,6 @@ public override void OnInspectorGUI() key_colors(); - if (ToggleButtonStyleNormal == null) { ToggleButtonStyleNormal = "Button"; @@ -63,11 +67,13 @@ public override void OnInspectorGUI() ToggleButtonStyleToggled.normal.background = ToggleButtonStyleToggled.active.background; } - //matte = (ZEDGarbageMatte)target; + //matte = (ZEDGarbageMatte)target; matte = greenScreen.garbageMatte; GUI.enabled = greenScreen.screenManager != null && greenScreen.screenManager.ActualRenderingPath == RenderingPath.Forward; enableGrabageMatte.boolValue = EditorGUILayout.Toggle("Enable Garbage Matte", enableGrabageMatte.boolValue); GUI.enabled = true; + + //Show the garbage matte section, only if the scene is running and it's enabled. if (enableGrabageMatte.boolValue && greenScreen.screenManager != null && greenScreen.screenManager.ActualRenderingPath == RenderingPath.Forward) { //serializedObject.Update(); @@ -104,6 +110,7 @@ public override void OnInspectorGUI() } } + //Draw the configuration file path and Save/Load buttons. GUILayout.Space(20); EditorGUILayout.BeginHorizontal(); pathfileconfig.stringValue = EditorGUILayout.TextField("Save Config", greenScreen.pathFileConfig); @@ -186,6 +193,7 @@ void key_colors() despill.floatValue = EditorGUILayout.Slider("Despill", despill.floatValue, 0f, 1f); + //Button to reset to default settings. GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Default", optionsButton)) diff --git a/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GarbageMatte.cs b/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GarbageMatte.cs index 3c14baff..767c34c1 100644 --- a/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GarbageMatte.cs +++ b/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GarbageMatte.cs @@ -10,49 +10,86 @@ #endif /// -/// Creates a mask from position and apply it on the pipeline +/// Creates a garbage matte mask from its position and apply it on the pipeline. +/// It's created by GreenScreenManager as a 3D object, that you can create from the Inspector by placing the bounds of the mesh. +/// The garbage matte represents a region of the screen where no real pixels will be rendered, regardless of depth. +/// This can be used to extend the bounds of a greenscreen when the physical screen isn't large enough to fill the background. /// [RequireComponent(typeof(GreenScreenManager))] [RequireComponent(typeof(Camera))] public class GarbageMatte { - // Reference to the ZED + /// + /// Reference to the ZEDCamera. + /// private sl.ZEDCamera zed; - //Position in queue to make transparent object, used to render the mesh transparent + /// + /// Position in the render queue used by Unity's renderer to render a mesh transparent. This gets appled to the shader. + /// private const int QUEUE_TRANSPARENT_VALUE = 3000; - //List of points to make the mesh + /// + /// List of 3D points used to make the matte mesh, eg the "corners". + /// private List points = new List(); - // The current camera looking the scene, used to transform ScreenPosition to worldPosition + /// + /// The current camera looking at the scene, used to transform ScreenPosition to worldPosition when placing the boundary points. + /// private Camera cam; - //List of the different gameObjects used by the mesh + /// + /// List of the gameObjects used by the mesh. + /// private List go = null; - //List of the meshes + /// + /// List of the meshes. + /// private List meshFilters; - //Triangles of the current mesh + /// + /// Triangles of the current mesh. + /// private List triangles = new List(); - private List spheresBorder = new List(); + /// + /// The sphere objects the user places via GreenScreenManager to define the bounds of the matte object. + /// + private List borderspheres = new List(); + + /// + /// The ZED greenscreen material. Usually Mat_ZED_GreenScreen. + /// private Material shader_greenScreen; + + /// + /// The material used on the spheres that the user places via GreenScreenManager to define the bounds of the matte object. + /// Usually Mat_ZED_Outlined. + /// private Material outlineMaterial; + + /// + /// Whether or not the maatte is currently being edited. + /// private bool isClosed = false; + /// + /// The index of meshFilters that refers to the plane mesh we're currently editing, if applicable. + /// private int currentPlaneIndex; + + /// + /// The Unity layer where spheres exist, for visibility reasons. + /// private int sphereLayer = 21; + /// + /// The Unity CommandBuffer that gets applied to the camera, which results in the matte getting rendered. + /// private CommandBuffer commandBuffer; - /*** OPTIONS TO CHANGE ****/ - //At launch, if no file are found, the GarbageMatte controls are activated if true. Button Fire1 || Fire2 - private bool isAbleToEdit = true; - // Apply the garbageMatte is per default on the button "return" - private string applyButton = "return"; - [SerializeField] [HideInInspector] public string garbageMattePath = "garbageMatte.cfg"; @@ -71,12 +108,12 @@ public bool IsInit get { return isInit; } } /// - /// Create the GarbageMatte class + /// Constructor that sets up the garbage matte for the desired camera in the desired place. /// - /// - /// - /// - /// + /// Camera in which to apply the matte effect + /// Material reference, usually Mat_ZED_Greenscreen + /// Center location of the matte effect + /// Optional reference to another garbage matte, used to copy its current edit mode. public GarbageMatte(Camera cam, Material greenScreenMaterial, Transform target, GarbageMatte matte) { this.target = target; @@ -126,7 +163,7 @@ public GarbageMatte(Camera cam, Material greenScreenMaterial, Transform target, } /// - /// Create a dummy garbage matte, do nothing. Should be used only as a cache in memory + /// Constructor to create a dummy garbage matte that does nothing. Should be used only as a cache in memory /// public GarbageMatte() { @@ -134,42 +171,6 @@ public GarbageMatte() } - - /// - /// Check if pad are ready to set the garbage matte points - /// - private void PadReady() - { - ResetPoints(false); - if (Load()) - { - Debug.Log("Config garbage matte found, and loaded ( " + garbageMattePath + " )"); - ApplyGarbageMatte(); - editMode = false; - } - else - { - if (isAbleToEdit) - { - editMode = true; - } - - } - - } - - private void OnEnable() - { - ZEDSteamVRControllerManager.ZEDOnPadIndexSet += PadReady; - } - - private void OnDisable() - { - ZEDSteamVRControllerManager.ZEDOnPadIndexSet -= PadReady; - - } - - private List indexSelected = new List(); private List currentGOSelected = new List(); private List meshFilterSelected = new List(); @@ -177,7 +178,7 @@ private void OnDisable() private int numberSpheresSelected = -1; /// - /// Update the garbage matte and manage the movement of the spheres + /// Update the garbage matte and manage the movement of the spheres. /// public void Update() { @@ -200,10 +201,10 @@ public void Update() if (zed != null && zed.IsCameraReady) { - //If left click, add a sphere + //If left mouse is clicked, add a sphere if (Input.GetMouseButtonDown(0)) { - //Add a new plan if needed + //Add a new plane if needed if (go.Count - 1 < currentPlaneIndex) { @@ -236,7 +237,7 @@ public void Update() //Create the planes if needed for (int i = 0; i < planeSelectedIndex.Count; ++i) { - if ((spheresBorder.Count - planeSelectedIndex[i] * 4) < 4) + if ((borderspheres.Count - planeSelectedIndex[i] * 4) < 4) { numberSpheresSelected = -1; planeSelectedIndex.Clear(); @@ -246,7 +247,7 @@ public void Update() points = new List(); for (int j = planeSelectedIndex[i] * 4; j < (planeSelectedIndex[i] + 1) * 4; j++) { - points.Add(spheresBorder[j].transform.position); + points.Add(borderspheres[j].transform.position); } CloseShape(triangles, points, planeSelectedIndex[i]); @@ -262,8 +263,8 @@ public void Update() RaycastHit hit; if (Physics.Raycast(target.position, (vec - target.position), out hit, 10, (1 << sphereLayer))) { - int hitIndex = spheresBorder.IndexOf(hit.transform.gameObject); - vec = spheresBorder[hitIndex].transform.position; + int hitIndex = borderspheres.IndexOf(hit.transform.gameObject); + vec = borderspheres[hitIndex].transform.position; } points.Add(vec); @@ -276,18 +277,18 @@ public void Update() sphere.transform.position = points[points.Count - 1]; sphere.layer = sphereLayer; - spheresBorder.Add(sphere); - if (spheresBorder.Count >= 2) + borderspheres.Add(sphere); + if (borderspheres.Count >= 2) { - spheresBorder[spheresBorder.Count - 2].GetComponent().material.SetFloat("_Outline", 0.00f); + borderspheres[borderspheres.Count - 2].GetComponent().material.SetFloat("_Outline", 0.00f); } - if (spheresBorder.Count % 4 == 0) + if (borderspheres.Count % 4 == 0) { points = new List(); for (int i = currentPlaneIndex * 4; i < (currentPlaneIndex + 1) * 4; i++) { - points.Add(spheresBorder[i].transform.position); + points.Add(borderspheres[i].transform.position); } CloseShape(triangles, points, currentPlaneIndex); EndPlane(); @@ -311,17 +312,17 @@ public void Update() for (int i = 0; i < hits.Length; ++i) { - int hitIndex = spheresBorder.IndexOf(hits[i].transform.gameObject); + int hitIndex = borderspheres.IndexOf(hits[i].transform.gameObject); indexSelected.Add(hitIndex); - currentGOSelected.Add(spheresBorder[hitIndex]); + currentGOSelected.Add(borderspheres[hitIndex]); planeSelectedIndex.Add(hitIndex / 4); meshFilterSelected.Add(meshFilters[planeSelectedIndex[planeSelectedIndex.Count - 1]]); - spheresBorder[hitIndex].GetComponent().material.SetFloat("_Outline", 0.02f); + borderspheres[hitIndex].GetComponent().material.SetFloat("_Outline", 0.02f); } numberSpheresSelected = hits.Length; - spheresBorder[spheresBorder.Count - 1].GetComponent().material.SetFloat("_Outline", 0.00f); + borderspheres[borderspheres.Count - 1].GetComponent().material.SetFloat("_Outline", 0.00f); } else @@ -332,32 +333,27 @@ public void Update() } } - //Apply the garbage matte - if (Input.GetKeyDown(applyButton)) - { - ApplyGarbageMatte(); - } } } /// - /// End the current plane and increase the index of plane + /// Finishes the current plane and increases the index of the plane /// - public void EndPlane() + private void EndPlane() { currentPlaneIndex++; ResetDataCurrentPlane(); } /// - /// + /// Enables editing the matte. /// public void EnterEditMode() { if (isClosed) { - foreach (GameObject s in spheresBorder) + foreach (GameObject s in borderspheres) { s.SetActive(true); } @@ -375,13 +371,16 @@ public void EnterEditMode() } } + /// + /// Removes the last sphere the user placed while defining the matte object's boundaries. + /// public void RemoveLastPoint() { //Prevent to remove and move a sphere at the same time if (numberSpheresSelected != -1) return; if (isClosed) { - foreach (GameObject s in spheresBorder) + foreach (GameObject s in borderspheres) { s.SetActive(true); } @@ -397,7 +396,7 @@ public void RemoveLastPoint() } isClosed = false; } - if (spheresBorder.Count % 4 == 0 && currentPlaneIndex > 0) + if (borderspheres.Count % 4 == 0 && currentPlaneIndex > 0) { GameObject.Destroy(go[currentPlaneIndex - 1]); go.RemoveAll(item => item == null); @@ -408,26 +407,33 @@ public void RemoveLastPoint() } - if (spheresBorder != null && spheresBorder.Count > 0) + if (borderspheres != null && borderspheres.Count > 0) { - GameObject.DestroyImmediate(spheresBorder[spheresBorder.Count - 1]); - spheresBorder.RemoveAt(spheresBorder.Count - 1); - if (spheresBorder.Count % 4 == 0 && spheresBorder.Count > 0) + GameObject.DestroyImmediate(borderspheres[borderspheres.Count - 1]); + borderspheres.RemoveAt(borderspheres.Count - 1); + if (borderspheres.Count % 4 == 0 && borderspheres.Count > 0) { - spheresBorder[spheresBorder.Count - 1].GetComponent().material.SetFloat("_Outline", 0.02f); + borderspheres[borderspheres.Count - 1].GetComponent().material.SetFloat("_Outline", 0.02f); } } } + /// + /// Clears the boundary points and triangles. Used before making a new plane, or when resetting all data. + /// private void ResetDataCurrentPlane() { points.Clear(); triangles.Clear(); } + /// + /// Removes existing sphere objects used to define bounds. + /// Used to ensure they're properly cleaned up when not being used to edit the garbage matte. + /// public void CleanSpheres() { GameObject[] remain_sphere2 = GameObject.FindGameObjectsWithTag ("HelpObject"); @@ -435,9 +441,12 @@ public void CleanSpheres() foreach (GameObject sph in remain_sphere2) GameObject.DestroyImmediate (sph); } - } + /// + /// Destroys all planes and spheres used to edit the matte to start from scratch. + /// + /// public void ResetPoints(bool cleansphere) { if (cleansphere) { @@ -461,14 +470,14 @@ public void ResetPoints(bool cleansphere) go.Clear(); meshFilters.Clear(); ResetDataCurrentPlane(); - if (spheresBorder != null) + if (borderspheres != null) { - foreach (GameObject s in spheresBorder) + foreach (GameObject s in borderspheres) { GameObject.DestroyImmediate(s); } } - spheresBorder.Clear(); + borderspheres.Clear(); if (commandBuffer != null) { commandBuffer.Clear(); @@ -479,21 +488,23 @@ public void ResetPoints(bool cleansphere) } /// - /// Get orientation + /// Helper function to determine a point's orientation along the plane. + /// Used by OrderPoints to sort vertices. /// /// /// /// /// /// - /// + /// 1 if it should be higher on the list, 0 if it should be lower. private static int Orientation(Vector3 p1, Vector3 p2, Vector3 p, Vector3 X, Vector3 Y) { return (Vector3.Dot(p2, X) - Vector3.Dot(p1, X)) * (Vector3.Dot(p, Y) - Vector3.Dot(p1, Y)) - (Vector3.Dot(p, X) - Vector3.Dot(p1, X)) * (Vector3.Dot(p2, Y) - Vector3.Dot(p1, Y)) > 0 ? 1 : 0; } /// - /// Ordering the points to draw a mesh + /// Orders the points in the points list in an order proper for drawing a mesh. + /// Points need to appear in the list in clockwise order within a triangle being drawn with them, around the plane's normal. /// /// private List OrderPoints(List points) @@ -505,7 +516,7 @@ private List OrderPoints(List points) Vector3 Y = Vector3.Cross(X, normal); Y.Normalize(); - List ordoredIndex = new List(); + List orderedIndex = new List(); List convexHull = new List(); float minX = Vector3.Dot(points[0], X); @@ -524,7 +535,7 @@ private List OrderPoints(List points) for (int i = 0; i < 4; i++) { convexHull.Add(p); - ordoredIndex.Add(points.IndexOf(p)); + orderedIndex.Add(points.IndexOf(p)); currentTestPoint = points[0]; for (int j = 0; j < points.Count; j++) { @@ -535,11 +546,11 @@ private List OrderPoints(List points) } p = currentTestPoint; } - return ordoredIndex; + return orderedIndex; } /// - /// Draw the last quad + /// Finish off the last quad mesh. /// public void CloseShape(List triangles, List points, int currentPlaneIndex) { @@ -564,12 +575,12 @@ public void CloseShape(List triangles, List points, int currentPla go[currentPlaneIndex].GetComponent().sharedMesh.vertices = points.ToArray(); go[currentPlaneIndex].GetComponent().sharedMesh.triangles = triangles.ToArray(); - spheresBorder[spheresBorder.Count - 1].GetComponent().material.SetFloat("_Outline", 0.00f); + borderspheres[borderspheres.Count - 1].GetComponent().material.SetFloat("_Outline", 0.00f); } /// - /// Apply the garbage matte by rendering into the stencil buffer + /// Apply the garbage matte by rendering into the stencil buffer. /// public void ApplyGarbageMatte() { @@ -583,7 +594,7 @@ public void ApplyGarbageMatte() if (shader_greenScreen != null) { isClosed = true; - foreach (GameObject s in spheresBorder) + foreach (GameObject s in borderspheres) { s.SetActive(false); } @@ -606,12 +617,15 @@ public void ApplyGarbageMatte() } editMode = false; } - private void OnApplicationQuit() { ResetPoints(true); } + /// + /// Create a hidden GameObject used to hold the editing components. + /// + /// private GameObject CreateGameObject() { GameObject plane = new GameObject("PlaneTest"); @@ -636,6 +650,9 @@ private Mesh CreateMesh() return m; } + /// + /// Represents a single plane to be made into a mesh, then a matte. + /// [System.Serializable] public struct Plane { @@ -643,6 +660,9 @@ public struct Plane public List vertices; } + /// + /// Holds all planes to be turned into mattes and the total number of meshes. + /// [System.Serializable] public struct GarbageMatteData { @@ -650,6 +670,10 @@ public struct GarbageMatteData public List planes; } + /// + /// Packages the current garbage matte into GarbageMatteData, which can be serialized/saved by GreenScreenEditor. + /// + /// Data ready to be serialized. public GarbageMatteData RegisterData() { GarbageMatteData garbageMatteData = new GarbageMatteData(); @@ -669,7 +693,11 @@ public GarbageMatteData RegisterData() return garbageMatteData; } - + /// + /// Loads a serialized GarbageMatteData instance to be used/viewed/edited. + /// + /// + /// True if there was actual data to load (at least one plane). public bool LoadData(GarbageMatteData garbageMatteData) { @@ -700,7 +728,7 @@ public bool LoadData(GarbageMatteData garbageMatteData) sphere.transform.position = points[points.Count - 1]; sphere.layer = sphereLayer; - spheresBorder.Add(sphere); + borderspheres.Add(sphere); } if (go.Count == 0) return false; @@ -711,7 +739,7 @@ public bool LoadData(GarbageMatteData garbageMatteData) } /// - /// Save the points into a file + /// Save the points into a file. /// public void Save() { @@ -769,7 +797,7 @@ public bool Load() sphere.tag = "HelpObject"; sphere.transform.position = points[points.Count - 1]; sphere.layer = sphereLayer; - spheresBorder.Add(sphere); + borderspheres.Add(sphere); } if (go.Count == 0) return false; diff --git a/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GreenScreenManager.cs b/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GreenScreenManager.cs index ed98d67e..4443d087 100644 --- a/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GreenScreenManager.cs +++ b/ZEDCamera/Assets/ZED/Examples/GreenScreen/Scripts/GreenScreenManager.cs @@ -1,27 +1,35 @@ //======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== - using UnityEngine; using System.IO; - /// -/// Creates a mask from a chroma key, and is used as an interface for the garbage matte +/// When attached to an object that also has a ZEDRenderingPlane, removes all real-world pixels +/// of a specified color. Useful for third-person mixed reality setups. +/// Also requires the Frame object of the ZEDRenderingPlane component to have its MeshRenderer material set to Mat_ZED_GreenScreen. +/// The simplest way to use the plugin's GreenScreen feature is to use the ZED_GreenScreen prefab in the GreenScreen sample folder. +/// For detailed information on using the ZED for greenscreen effects, see https://docs.stereolabs.com/mixed-reality/unity/green-screen-vr/. /// [RequireComponent(typeof(ZEDRenderingPlane))] public class GreenScreenManager : MonoBehaviour { /// - /// The plane used for rendering + /// The plane used for rendering. Equal to the canvas value of ZEDRenderingPlane. /// private GameObject screen = null; + /// - /// The screen manager script + /// The screen manager script. Automatically assigned in OnEnable(). /// public ZEDRenderingPlane screenManager = null; + /// + /// Set to true when there is data available from a configuration file that needs to be loaded. + /// It will then be loaded the next call to Update(). + /// private bool toUpdateConfig = false; + /// - /// Chroma key settings + /// Holds chroma key settings together in a single serializable object. /// [System.Serializable] public struct ChromaKey @@ -31,7 +39,7 @@ public struct ChromaKey public float range; } /// - /// Chroma key data + /// Holds chroma key data together in a single serializable object. /// [System.Serializable] public struct ChromaKeyData @@ -45,6 +53,9 @@ public struct ChromaKeyData public float spill; } + /// + /// Holds greenscreen and garbage matte configuration data together in a single serializable object. + /// [System.Serializable] public struct GreenScreenData { @@ -62,76 +73,78 @@ public struct GreenScreenData [SerializeField] public Color keyColors = new Color(0.0f, 1.0f, 0.0f, 1); /// - /// Array of available similarity + /// Causes pixels on the edge of the range to the color to fade out, instead of all pixels being 100% or 0% visible. /// [SerializeField] public float smoothness; /// - /// Array of available blend + /// Governs how similar a pixel must be to the chosen color to get removed. /// - [SerializeField] public float range; /// - /// Array of available blend + /// subtracts the color value from the foreground image, making it appear "less green" for instance. + /// Useful because bright lighting can cause the color of a greenscreen to spill onto your actual subject. /// - /// [SerializeField] public float spill = 0.2f; /// - /// Default color for chroma key + /// Default green color for the chroma key. /// private Color defaultColor = new Color(0.0f, 1.0f, 0.0f, 1); /// - /// DEfault similarity + /// Default Smoothness value. /// private const float defaultSmoothness = 0.08f; /// - /// Default blend + /// Default Range value. /// private const float defaultRange = 0.42f; /// - /// Default blend + /// Default Spill value. /// private const float defaultSpill = 0.1f; /// - /// Default erosion + /// Default Erosion value. /// private const int defaultErosion = 0; /// - /// Default white clip + /// Default White Clip value. /// private const float defaultWhiteClip = 1.0f; /// - /// Default black clip + /// Default Black Clip value. /// private const float defaultBlackClip = 0.0f; /// - /// Default sigma + /// Default sigma. /// private const float defaultSigma = 0.1f; - /// - /// Final rendering material + /// Final rendering material, eg. the material on the ZEDRenderingPlane's canvas object. /// public Material finalMat; /// - /// Green screen effect material + /// Green screen effect material. /// private Material greenScreenMat; - + /// + /// Material used to apply preprocessing effects in OnPreRender. + /// private Material preprocessMat; - /// - /// Alpha texture for blending + /// Alpha texture for blending. /// private RenderTexture finalTexture; + /// + /// Public accessor for the alpha texture used for blending. + /// public RenderTexture FinalTexture { get { return finalTexture; } } /// - /// Available canals for display chroma key effect + /// Available canals (views) for displaying the chroma key effect. /// public enum CANAL { @@ -142,67 +155,84 @@ public enum CANAL FINAL }; /// - /// Current canal used + /// The current view. Change to see different steps of the rendering stage, which can be helpful for tweaking other settings. /// [HideInInspector] [SerializeField] public CANAL canal = CANAL.FINAL; /// - /// Erosion value + /// Carves off pixels from the edges between the foreground and background. /// [HideInInspector] [SerializeField] public int erosion = 0; /// - /// CutOff value + /// Causes pixels with alpha values above its setting to be set to 100% alpha, useful for reducing noise resulting from the smoothness setting. /// [SerializeField] public float whiteClip = 1.0f; + /// + /// Causes pixels with alpha values below its setting to be set to 0% alpha, useful for reducing noise resulting from the smoothness setting. + /// [SerializeField] public float blackClip = 0.0f; /// - /// Green screen shader name + /// The path to the .config file, where configurations would be loaded or saved when you press the relevant button. /// [SerializeField] public string pathFileConfig = "Assets/Config_greenscreen.json"; - /// - /// Blur material + /// Material used to apply blur effect in OnPreRender(). /// private Material blurMaterial; /// - /// Blur iteration number. A larger value increase blur effect. + /// Blur iteration number. A larger value increases the blur effect. /// public int numberBlurIterations = 5; /// - /// Sigma value. A larger value increase blur effect. + /// Sigma value. A larger value increases the blur effect. /// public float sigma_ = 0.1f; /// - /// Current sigma value + /// Current sigma value. /// private float currentSigma = -1; /// - /// Weights for blur + /// Weights for blur effect. /// private float[] weights_ = new float[5]; /// - /// Offsets for blur + /// Offsets for blur effect. /// private float[] offsets_ = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f }; - - + /// + /// Material used to convert an RGBA texture into YUV, which makes it simpler to add certain effects. + /// public Material matYUV; + /// + /// Reference to the currently active GarbageMatte. + /// We make an empty one regardless of the enableGarbageMatte setting so a reference to one is always available. + /// [SerializeField] [HideInInspector] public GarbageMatte garbageMatte = new GarbageMatte(); + /// + /// Whether we're using the garbage matte effect or not. + /// public bool enableGarbageMatte = false; + /// + /// All the data for the garbage matte. + /// private GarbageMatte.GarbageMatteData garbageMatteData; + + /// + /// Sets all settings to the default values. Called on a new component, and when Reset is clicked. + /// public void SetDefaultValues() { keyColors = defaultColor; @@ -215,6 +245,11 @@ public void SetDefaultValues() sigma_ = defaultSigma; } + /// + /// Sets up the greenscreen with saved data. + /// Used exclusively by ZEDSteamVRControllerManager to make sure this happens after controllers are set up. + /// Otherwise, included logic gets set elsewhere in different places. + /// public void PadReady() { if (garbageMatteData.numberMeshes != 0 && garbageMatte != null) @@ -244,8 +279,6 @@ private void OnDisable() ZEDSteamVRControllerManager.ZEDOnPadIndexSet -= PadReady; } - - private void Awake() { Shader.SetGlobalInt("_ZEDStencilComp", 0); @@ -268,24 +301,29 @@ private void Awake() #endif } + /// + /// Holds whether we need to apply the DEPTH_ALPHA keyword to the ZED imagefirst pass material (Mat_ZED_Forward) + /// which causes it to process the greenscreen mask. + /// private bool textureOverlayInit = false; private void Update() { - if(screenManager != null && !textureOverlayInit) + if(screenManager != null && !textureOverlayInit) //Need to tell the shader to apply the mask. { - if(screenManager.ManageKeyWordForwardMat(true, "DEPTH_ALPHA")) + if(screenManager.ManageKeywordForwardMat(true, "DEPTH_ALPHA")) { textureOverlayInit = true; } } - if (toUpdateConfig) + if (toUpdateConfig) //Need to load available greenscreen configuration data into the current, active data. { toUpdateConfig = false; LoadGreenScreenData(); } - if (enableGarbageMatte) + + if (enableGarbageMatte) //Set up the garbage matte if needed. { if (garbageMatte != null && garbageMatte.IsInit) { @@ -298,9 +336,13 @@ private void Update() } } - + /// + /// Initialization logic that must be done after the ZED camera has finished initializing. + /// Added to the ZEDManager.OnZEDReady() callback in OnEnable(). + /// private void ZEDReady() { + //Set up textures and materials used for the final output. finalTexture = new RenderTexture(sl.ZEDCamera.GetInstance().ImageWidth, sl.ZEDCamera.GetInstance().ImageHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); finalTexture.SetGlobalShaderProperty("ZEDMaskTexGreenScreen"); finalMat.SetTexture("_MaskTex", finalTexture); @@ -313,7 +355,7 @@ private void ZEDReady() preprocessMat.SetTexture("_CameraTex", screenManager.TextureEye); ZEDPostProcessingTools.ComputeWeights(1, out weights_, out offsets_); - //Send the values to the current shader + //Send the values to the current shader. blurMaterial.SetFloatArray("weights2", weights_); blurMaterial.SetFloatArray("offset2", offsets_); greenScreenMat.SetTexture("_CameraTex", screenManager.TextureEye); @@ -325,31 +367,32 @@ private void ZEDReady() sl.ZEDCamera.GetInstance().LoadCameraSettings("ZED_Settings.conf"); sl.ZEDCamera.GetInstance().SetCameraSettings(); } - } - - /// - /// Update the current canal (VIEW) + /// Update the current canal (VIEW) to the setting in the editor. + /// The greenscreen shader uses #ifdef keywords to render differently depending on the active canal. + /// This class makes sure that exactly one such keyword is defined at one time. /// public void UpdateCanal() { - foreach (CANAL c in System.Enum.GetValues(typeof(CANAL))) + foreach (CANAL c in System.Enum.GetValues(typeof(CANAL))) //Clear all keywords { manageKeyWord(false, c.ToString()); } if (screenManager != null) { - if (canal == CANAL.BACKGROUND) screenManager.ManageKeyWordForwardMat(true, "NO_DEPTH"); - else screenManager.ManageKeyWordForwardMat(false, "NO_DEPTH"); - manageKeyWord(true, canal.ToString()); + //Set NO_DEPTH keyword as well if set to BACKGROUND. + if (canal == CANAL.BACKGROUND) screenManager.ManageKeywordForwardMat(true, "NO_DEPTH"); + else screenManager.ManageKeywordForwardMat(false, "NO_DEPTH"); + + manageKeyWord(true, canal.ToString()); //Activate the keyword corresponding to the current Canal. } } /// - /// Enable or disable a keyword + /// Enables or disables a shader keyword in the finalMat material. /// /// /// @@ -358,8 +401,7 @@ void manageKeyWord(bool value, string name) if (finalMat != null) { if (value) - { - + { finalMat.EnableKeyword(name); } else @@ -370,18 +412,18 @@ void manageKeyWord(bool value, string name) } #if UNITY_EDITOR - private void OnValidate() + private void OnValidate() //When the Inspector is visible and it changes somehow. { UpdateShader(); } #endif - private void OnApplicationQuit() + private void OnApplicationQuit() { if (finalTexture != null && finalTexture.IsCreated()) finalTexture.Release(); } - public void Reset() + public void Reset() //When the Unity editor Reset button is used. { ZEDManager zedManager = null; @@ -394,6 +436,12 @@ public void Reset() SetDefaultValues(); } + /// + /// Helper function to convert colors in RGB color space to YUV format. + /// + /// Color to be converted. + /// Whether to keep the values within the maximum. + /// Vector3 RGBtoYUV(Color rgb, bool clamped = true) { double Y = 0.182586f * rgb.r + 0.614231f * rgb.g + 0.062007f * rgb.b + 0.062745f; // Luma @@ -409,8 +457,8 @@ Vector3 RGBtoYUV(Color rgb, bool clamped = true) /// - /// Update all the data to the shader - /// The weights and offsets will be set when sigma change + /// Update all the data to the greenscreen shader. + /// The weights and offsets will be set when sigma changes. /// public void UpdateShader() { @@ -430,9 +478,9 @@ public void UpdateShader() } /// - /// Load the data from a file and fill a structure + /// Load the data from a file and fills a structure. /// - /// + /// Whether there's a valid file where pathFileConfig says there is. private bool LoadData(out GreenScreenData gsData) { gsData = new GreenScreenData(); @@ -447,7 +495,7 @@ private bool LoadData(out GreenScreenData gsData) } /// - /// Save the chroma keys used in a file (JSON format) + /// Creates a new serializable ChromaKeyData file from the current settings. /// public ChromaKeyData RegisterDataChromaKeys() { @@ -469,7 +517,7 @@ public ChromaKeyData RegisterDataChromaKeys() } /// - /// Return a string from a pointer to char + /// Saves the chroma keys used in a file (JSON format). /// public void SaveData(ChromaKeyData chromaKeyData, GarbageMatte.GarbageMatteData garbageMatteData) { @@ -482,9 +530,9 @@ public void SaveData(ChromaKeyData chromaKeyData, GarbageMatte.GarbageMatteData } /// - /// Fill the current chroma keys with the data from a file + /// Fills the current chroma keys with the data from a file. /// - public void LoadGreenScreenData(bool forceGargabeMatte = false) + public void LoadGreenScreenData(bool forcegarbagemate = false) { GreenScreenData gsData; if (LoadData(out gsData)) @@ -506,7 +554,7 @@ public void LoadGreenScreenData(bool forceGargabeMatte = false) UpdateShader(); - if (forceGargabeMatte && garbageMatte != null) + if (forcegarbagemate && garbageMatte != null) { if (!garbageMatte.IsInit) { @@ -520,7 +568,7 @@ public void LoadGreenScreenData(bool forceGargabeMatte = false) /// - /// Return a string from a pointer to char + /// Where various image processing effects are applied, including the green screen effect itself. /// private void OnPreRender() { @@ -536,7 +584,7 @@ private void OnPreRender() Graphics.Blit(screenManager.TextureEye, tempFinalAlpha, preprocessMat); - //If the sigma has changed recompute the weights and offsets used by the blur + //If the sigma has changed, recompute the weights and offsets used by the blur. if (sigma_ == 0) { if (sigma_ != currentSigma) @@ -561,19 +609,26 @@ private void OnPreRender() RenderTexture.ReleaseTemporary(tempFinalAlpha); } + /// + /// Gets a value within a gaussian spread defined by sigma. + /// float Gaussian(float x, float sigma) { return (1.0f / (2.0f * Mathf.PI * sigma)) * Mathf.Exp(-((x * x) / (2.0f * sigma))); } + /// + /// Watch for changes in LastAccess and LastWrite times, and the renaming of files or directories. + /// Used to make sure the path to the config file remains valid. + /// + /// public void CreateFileWatcher(string path) { if (!File.Exists(pathFileConfig)) return; FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = path; - /* Watch for changes in LastAccess and LastWrite times, and - the renaming of files or directories. */ + watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher.Filter = Path.GetFileName(pathFileConfig); @@ -582,10 +637,11 @@ the renaming of files or directories. */ watcher.EnableRaisingEvents = true; } - // Define the event handlers. + /// + /// Event handler for when the path to the config file changes while within the editor. + /// private void OnChanged(object source, FileSystemEventArgs e) { toUpdateConfig = true; - } } diff --git a/ZEDCamera/Assets/ZED/Examples/Movie Screen/Scenes/Movie Screen.unity b/ZEDCamera/Assets/ZED/Examples/Movie Screen/Scenes/Movie Screen.unity index 62c99a0d..5c0d2946 100644 --- a/ZEDCamera/Assets/ZED/Examples/Movie Screen/Scenes/Movie Screen.unity +++ b/ZEDCamera/Assets/ZED/Examples/Movie Screen/Scenes/Movie Screen.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.4366757, g: 0.48427194, b: 0.5645252, a: 1} + m_IndirectSpecularColor: {r: 0.17276844, g: 0.21589246, b: 0.2978263, a: 1} --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 @@ -77,15 +77,17 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVRFiltering: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousColorSigma: 1 - m_PVRFilteringAtrousNormalSigma: 1 - m_PVRFilteringAtrousPositionSigma: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -276,8 +278,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 454b1f0b0de2bb644a283d964ccf7f06, type: 3} m_Name: m_EditorClassIdentifier: + index: -1 deviceToTrack: 0 - _latencyCompensation: 78 + latencyCompensation: 78 + SNHolder: --- !u!4 &143983926 Transform: m_ObjectHideFlags: 0 @@ -1048,8 +1052,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 454b1f0b0de2bb644a283d964ccf7f06, type: 3} m_Name: m_EditorClassIdentifier: + index: -1 deviceToTrack: 1 - _latencyCompensation: 78 + latencyCompensation: 78 + SNHolder: --- !u!4 &1662357131 Transform: m_ObjectHideFlags: 0 @@ -1216,11 +1222,10 @@ MonoBehaviour: m_EditorClassIdentifier: motion: 0 invertRotation: 0 - VRControls: 0 - MovementSpeed: 0.5 - RotationSpeed: 1 - ScaleSpeed: 0.25 - UpDownSpeed: 0.5 + repositionAtStart: 1 + movementSpeed: 0.5 + rotationSpeed: 0.1 + scaleSpeed: 0.25 maxScale: 2 minScale: 0.25 spotLight: {fileID: 623047055} diff --git a/ZEDCamera/Assets/ZED/Examples/Object Placement/Scene/ObjectPlacement.unity b/ZEDCamera/Assets/ZED/Examples/Object Placement/Scene/ObjectPlacement.unity index a119f583..a251123f 100644 --- a/ZEDCamera/Assets/ZED/Examples/Object Placement/Scene/ObjectPlacement.unity +++ b/ZEDCamera/Assets/ZED/Examples/Object Placement/Scene/ObjectPlacement.unity @@ -263,7 +263,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b9be17ee14023ff448b02279f7e0f0fd, type: 3} m_Name: m_EditorClassIdentifier: - Object: {fileID: 100074, guid: be66986effd141b4992d2d78be127139, type: 3} + ObjectToPlace: {fileID: 100074, guid: be66986effd141b4992d2d78be127139, type: 3} --- !u!4 &2123395079 Transform: m_ObjectHideFlags: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/Object Placement/Scripts/PlaceOnScreen.cs b/ZEDCamera/Assets/ZED/Examples/Object Placement/Scripts/PlaceOnScreen.cs index ca9ce04f..fb621104 100644 --- a/ZEDCamera/Assets/ZED/Examples/Object Placement/Scripts/PlaceOnScreen.cs +++ b/ZEDCamera/Assets/ZED/Examples/Object Placement/Scripts/PlaceOnScreen.cs @@ -2,20 +2,35 @@ using System.Collections.Generic; using UnityEngine; -public class PlaceOnScreen : MonoBehaviour { +/// +/// Spawns an object when you click on the screen at the real-world position clicked. +/// Will only spawn an object if the surface clicked is facing upward. +/// Note that the ZED's newer plane detection feature is usually better for this unless +/// you need something very simple. +/// +public class PlaceOnScreen : MonoBehaviour +{ + /// + /// Prefab object to be instantiated in the real world on a click. + /// + public GameObject ObjectToPlace; - ZEDManager ZedManager; - Camera LeftCamera; + /// + /// The ZEDManager in the scene. + /// + private ZEDManager ZedManager; - public GameObject Object; + /// + /// The left camera in the ZED rig. Passed to ZEDSupportFunctions for transforming between camera and world space. + /// + private Camera LeftCamera; // Use this for initialization void Awake() { ZedManager = FindObjectOfType(); LeftCamera = ZedManager.GetLeftCameraTransform().gameObject.GetComponent(); - // Show cursor - Cursor.visible = true; + Cursor.visible = true; //Make sure cursor is visible so we can click on the world accurately. } // Update is called once per frame @@ -25,34 +40,33 @@ void Update () { return; } - if (Input.GetMouseButtonDown(0)) + if (Input.GetMouseButtonDown(0)) //Checks for left click. { /// Mouse Input gives the screen pixel position Vector2 ScreenPosition = Input.mousePosition; + //Get Normal and real world position defined by the pixel . Vector3 Normal; Vector3 WorldPos; - - // Get Normal and real world position defined by the pixel ZEDSupportFunctions.GetNormalAtPixel(ScreenPosition,sl.REFERENCE_FRAME.WORLD,LeftCamera,out Normal); ZEDSupportFunctions.GetWorldPositionAtPixel(ScreenPosition, LeftCamera,out WorldPos); - - // To consider the location as a floor, we check that the normal is valid and is closely aligned with the gravity + //To consider the location as a flat surface, we check that the normal is valid and is closely aligned with gravity. bool validFloor = Normal.x != float.NaN && Vector3.Dot(Normal, Vector3.up) > 0.85f; - // If we've found a floor to place the bunny, then set its location and show it. - if (validFloor) { - GameObject newbunny = Instantiate(Object); - newbunny.transform.localPosition = WorldPos; - newbunny.transform.LookAt(new Vector3(ZedManager.transform.position.x, newbunny.transform.position.y, ZedManager.transform.position.z), Vector3.up); - newbunny.SetActive(true); - } else { + //If we've found a floor to place the object, spawn a copy of the prefab. + if (validFloor) + { + GameObject newgo = Instantiate(ObjectToPlace); + newgo.transform.localPosition = WorldPos; + newgo.transform.LookAt(new Vector3(ZedManager.transform.position.x, newgo.transform.position.y, ZedManager.transform.position.z), Vector3.up); + } + else + { if (Normal.x == float.NaN) - Debug.Log ("cannot place object at this position. Normal vector not detected."); + Debug.Log ("Cannot place object at this position. Normal vector not detected."); if (Vector3.Dot(Normal, Vector3.up) <= 0.85f) - Debug.Log ("cannot place object at this position. Normal vector angled too far from up: "+Mathf.Acos(Vector3.Dot(Normal, Vector3.up))*Mathf.Rad2Deg + "°"); - Object.SetActive(false); + Debug.Log ("Cannot place object at this position. Normal vector angled too far from up: "+Mathf.Acos(Vector3.Dot(Normal, Vector3.up))*Mathf.Rad2Deg + "°"); } } } diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/Simple Plane Detection.unity b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/Simple Plane Detection.unity index 1c3b084d..2d4cf400 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/Simple Plane Detection.unity +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/Simple Plane Detection.unity @@ -241,19 +241,19 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d0abc0576042adc45b8f05b0d971b044, type: 3} m_Name: m_EditorClassIdentifier: - _bunnyPrefab: {fileID: 1791071174324572, guid: 0bcfb109574c6044a8d247157698abd6, + bunnyPrefab: {fileID: 1791071174324572, guid: 0bcfb109574c6044a8d247157698abd6, type: 2} - _laserPointerPrefab: {fileID: 1013873881802346, guid: 059643d321daca8498088bf53a3c033d, + pointerPrefab: {fileID: 1013873881802346, guid: 059643d321daca8498088bf53a3c033d, type: 2} - _canPlaceHolder: 0 - _uiPrefab: {fileID: 1113032969764556, guid: e118d12ab4eb21e488383f4b65090bd9, type: 2} - _currentBunny: {fileID: 0} - _baseballBat: {fileID: 0} - _placeHolderMat: - - {fileID: 2100000, guid: 1afc1a2666b033a4b9ee6e36cb577b8a, type: 2} + uiPrefab: {fileID: 1113032969764556, guid: e118d12ab4eb21e488383f4b65090bd9, type: 2} + placeHolderMat: - {fileID: 2100000, guid: 8c191c3046c025b4584bcfcf4a5f46ce, type: 2} - _rayOrigin: {fileID: 1184139381} - canSpawnMoreBunnies: 0 + - {fileID: 2100000, guid: 1afc1a2666b033a4b9ee6e36cb577b8a, type: 2} + rayOrigin: {fileID: 0} + canSpawnMultipleBunnies: 0 + canDisplayPlaceholder: 0 + currentBunny: {fileID: 0} + baseballBat: {fileID: 0} --- !u!4 &383434826 Transform: m_ObjectHideFlags: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/VR Only Plane Detection.unity b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/VR Only Plane Detection.unity index faf5ca46..eaafbe0d 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/VR Only Plane Detection.unity +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scenes/VR Only Plane Detection.unity @@ -77,15 +77,17 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVRFiltering: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousColorSigma: 1 - m_PVRFilteringAtrousNormalSigma: 1 - m_PVRFilteringAtrousPositionSigma: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -115,6 +117,11 @@ Prefab: m_Modification: m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: placeHolderMat.Array.size + value: 2 + objectReference: {fileID: 0} - target: {fileID: 114762965782928386, guid: 201563e25e8761a40adb2b278a2fb4f7, type: 2} propertyPath: badPlacementTex.Array.size @@ -200,6 +207,63 @@ Prefab: propertyPath: _rayOrigin value: objectReference: {fileID: 406601174} + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: bunnyPrefab + value: + objectReference: {fileID: 1791071174324572, guid: 0bcfb109574c6044a8d247157698abd6, + type: 2} + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: pointerPrefab + value: + objectReference: {fileID: 1013873881802346, guid: 059643d321daca8498088bf53a3c033d, + type: 2} + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: rayOrigin + value: + objectReference: {fileID: 406601174} + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: uiPrefab + value: + objectReference: {fileID: 1113032969764556, guid: e118d12ab4eb21e488383f4b65090bd9, + type: 2} + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: placeHolderMat.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 8c191c3046c025b4584bcfcf4a5f46ce, type: 2} + - target: {fileID: 114380879406418918, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: placeHolderMat.Array.data[1] + value: + objectReference: {fileID: 2100000, guid: 1afc1a2666b033a4b9ee6e36cb577b8a, type: 2} + - target: {fileID: 114278110183374612, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: capsulefollowerprefab + value: + objectReference: {fileID: 114284262561179570, guid: 426deaf652deccc4ab8025e0222d5b0a, + type: 2} + - target: {fileID: 114819210581546514, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: capsulefollowerprefab + value: + objectReference: {fileID: 114284262561179570, guid: 426deaf652deccc4ab8025e0222d5b0a, + type: 2} + - target: {fileID: 114397233949422500, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: capsulefollowerprefab + value: + objectReference: {fileID: 114284262561179570, guid: 426deaf652deccc4ab8025e0222d5b0a, + type: 2} + - target: {fileID: 114828685860240006, guid: 201563e25e8761a40adb2b278a2fb4f7, + type: 2} + propertyPath: capsulefollowerprefab + value: + objectReference: {fileID: 114284262561179570, guid: 426deaf652deccc4ab8025e0222d5b0a, + type: 2} m_RemovedComponents: [] m_ParentPrefab: {fileID: 100100000, guid: 201563e25e8761a40adb2b278a2fb4f7, type: 2} m_IsPrefabParent: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Bunny.cs b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Bunny.cs index 3c621393..2f2d170b 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Bunny.cs +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Bunny.cs @@ -2,51 +2,82 @@ using System.Collections.Generic; using UnityEngine; -public class Bunny : MonoBehaviour { - - //Reference to the Rigidbody of this object. - private Rigidbody _rb; - //Variable to store our initial position when we are enabled/spawned into the scene. - public Vector3 _savedPos { get; private set; } - //Boolean that is true whenever this object is moved by the baseball bat. - public bool _moving { get; private set; } - //Reference to the ZED's left camera gameobject. - private Camera _leftCamera; - //Reference to the BunnySpawner that spawned this gameObject. - private BunnySpawner _mySpawner; - //The transform to be used as new center/pivot point for this gameObject when checking for collisions with the real world. - private Transform _centerPoint; - //Reference to the ZED Plane Detection Manager. - private ZEDPlaneDetectionManager _zedPlane; - //Reference to the Animator. - [HideInInspector] - public Animator anim; +/// +/// Governs the FlyingBunny prefab used in the ZED plane detection samples. +/// Checks for collisions in front of it in midair, and spawns the flag when it hits the ground. +/// +public class Bunny : MonoBehaviour +{ + /// + /// Stores initial position when we are enabled/spawned into the scene. + /// Used to calculate how far the bunny traveled after we hit it in the VR plane detection demo. + /// + public Vector3 InitialPosition { get; private set; } + + /// + /// True whenever this object is moved by the baseball bat. + /// + public bool IsMoving { get; private set; } + + /// + /// Reference to the ZED rig's left camera component. + /// + private Camera leftcamera; + + /// + /// Reference to the BunnySpawner that spawned this GameObject. + /// + private BunnySpawner bunnyspawner; + + /// + /// The transform used as center/pivot point for this GameObject when checking for collisions with the real world. + /// + private Transform centerpoint; + + /// + /// Reference to the scene's ZED Plane Detection Manager. + /// + private ZEDPlaneDetectionManager planeManager; + + /// + /// The bunny's Rigidbody component. + /// + private Rigidbody rb; + /// - /// Use this for initialization. - /// Setting up the variables, and start up states. + /// The Bunny's Animator component. /// + [HideInInspector] + public Animator anim; + + // Use this for initialization. void Start() { //Find the left camera object if we didn't assign it at start. - if (!_leftCamera) + if (!leftcamera) { - _leftCamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); + leftcamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); } - //we're not moving at start. - _moving = false; - //Get our Rigidbody component. - _rb = GetComponent(); - //Saving our initial position. - _savedPos = transform.position; - //Getting the ZEDPlaneDetectionManager.cs component. - _zedPlane = FindObjectOfType(); + + IsMoving = false; //we're not moving at start. + + //Caching + planeManager = FindObjectOfType(); + rb = GetComponent(); //Get our Rigidbody component. + anim = GetComponent(); + + InitialPosition = transform.position; //Save for calculating distance traveled later. + //If there is a child in position 2, use it as new centerPoint. if (transform.GetChild(2) != null) - _centerPoint = transform.GetChild(2); - else //use this transform. - _centerPoint = transform; - //Get the Animator component. - anim = GetComponent(); + { + centerpoint = transform.GetChild(2); + } + else //If not, use this transform. + { + centerpoint = transform; + } + } /// @@ -55,7 +86,7 @@ void Start() /// public void SetMySpawner(BunnySpawner spawner) { - _mySpawner = spawner; + bunnyspawner = spawner; } /// @@ -72,28 +103,27 @@ public void GetHit(bool hit) /// Coroutine used to delay the collision detection of the Bunny. /// Setting the _moving variable after waiting X seconds. /// - /// IEnumerator HitDelay(bool hit) { //Wait for X amount of seconds... yield return new WaitForSeconds(0.1f); if (hit) { - //... then set _moving to true, and allow collision detection in FixedUpdate(). - _moving = true; + //... then set IsMoving to true, and allow collision detection in FixedUpdate(). + IsMoving = true; } else { - _rb.isKinematic = true; //Freeze the object at the current position. + rb.isKinematic = true; //Freeze the object at the current position. yield return new WaitForSeconds(1f); - _mySpawner.SpawnUI(transform.position); + bunnyspawner.SpawnUI(transform.position); } //Clearing the scene from any Planes created by the ZED Plane Detection Manager. - for (int i = 0; i < _zedPlane.hitPlaneList.Count; i++) + for (int i = 0; i < planeManager.hitPlaneList.Count; i++) { - Destroy(_zedPlane.hitPlaneList[i].gameObject); - _zedPlane.hitPlaneList.RemoveAt(i); + Destroy(planeManager.hitPlaneList[i].gameObject); + planeManager.hitPlaneList.RemoveAt(i); } } @@ -104,26 +134,25 @@ IEnumerator HitDelay(bool hit) private void FixedUpdate() { //If we have been moved by the baseball bat - if (_moving) + if (IsMoving) { //Look for our next position based on our current velocity. - Vector3 predictedPos = _centerPoint.position + (_rb.velocity * (Time.deltaTime * 2.5f)); - transform.rotation = Quaternion.LookRotation(_rb.velocity.normalized); + Vector3 predictedPos = centerpoint.position + (rb.velocity * (Time.deltaTime * 2.5f)); + transform.rotation = Quaternion.LookRotation(rb.velocity.normalized); //Collision check with the real world at that next position. - if (ZEDSupportFunctions.HitTestAtPoint(_leftCamera, predictedPos)) + if (ZEDSupportFunctions.HitTestAtPoint(leftcamera, predictedPos)) { //We hit something, but is it a flat surface? - if (_zedPlane.DetectPlaneAtHit(_leftCamera.WorldToScreenPoint(predictedPos))) + if (planeManager.DetectPlaneAtHit(leftcamera.WorldToScreenPoint(predictedPos))) { - _mySpawner.SpawnUI(predictedPos); - _moving = false; + bunnyspawner.SpawnUI(predictedPos); + IsMoving = false; } - else//If not freeze on hit. + else//If not, bounce off of it but still show the flag. { - //_rb.isKinematic = true; //Freeze the object at the current position. - _moving = false; //Not moving anymore, so update our state. - _mySpawner.SpawnUI(predictedPos); //Start spawning the UI on our current location. - _rb.velocity = Vector3.Reflect(_rb.velocity /2 , transform.forward); + IsMoving = false; //Not moving anymore, so update our state. + bunnyspawner.SpawnUI(predictedPos); //Start spawning the UI on our current location. + rb.velocity = Vector3.Reflect(rb.velocity /2 , transform.forward); //Bounce off the surface we hit } } } diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnyPlacement.cs b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnyPlacement.cs index 7480f781..920c375a 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnyPlacement.cs +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnyPlacement.cs @@ -3,30 +3,75 @@ using System.Collections; using System; +/// +/// Handles detecting whether or not a real-world location is valid for placing a Bunny object +/// in the ZED plane detection samples. To be valid, it must find a plane at the given location +/// and that plane must face upward. Turns a placeholder object blue when valid, and red when not. +/// Also works with VR controllers if the SteamVR or Oculus Integration plugins are installed. +/// public class BunnyPlacement : MonoBehaviour { - //Positive Color for placement + /// + /// Textures assigned to the placeholder object when placement is valid. + /// Index of each texture corresponds to the index of the material on the placeholder object. + /// + [Tooltip("Textures assigned to the placeholder object when placement is valid. " + + "Index of each texture corresponds to the index of the material on the placeholder object.")] public Texture[] goodPlacementTex; - //Negative Color for placement + + /// + /// Textures assigned to the placeholder object when placement is not valid. + /// Index of each texture corresponds to the index of the material on the placeholder object. + /// + [Tooltip("Textures assigned to the placeholder object when placement is not valid. " + + "Index of each texture corresponds to the index of the material on the placeholder object.")] public Texture[] badPlacementTex; - //Point Light - private Light pointLight; - // Reference to the Object Tracker. - private ZEDControllerTracker trackedObj; + + /// + /// Light object in the placeholder object. We change its color based on placement validity. + /// + private Light pointlight; + + /// + /// The ZEDControllerTracker object in the VR controller used to place the object, if applicable. + /// + private ZEDControllerTracker tracker; + #if ZED_STEAM_VR - // Reference to the SteamVR Controller for Input purposes. + /// + /// Reference to the SteamVR Controller for Input purposes. + /// SteamVR_Controller.Device device; #endif - //Reference to the ZED Plane Detection Manager. + + /// + /// The scene's ZED Plane Detection Manager. + /// private ZEDPlaneDetectionManager zedPlane; - //Reference to the BunnySpawner. + + /// + /// The BunnySpawner object, normally on the same object as this component. + /// private BunnySpawner bunnySpawner; - //Reference to the ZED's left camera gameobject. + + /// + /// The ZED rig's left camera component. Passed to ZEDSupportFunctions.cs for transforming between world and camera space. + /// private Camera leftCamera; - //Reference to the pointerBead transform. - private Transform pointerBead; - //Boolean that enables us to spawn or not the Bunny prefab. - private bool _canSpawnBunny; + + /// + /// The placeholder object's transform. + /// + private Transform placeholder; + + /// + /// Whether or not we are able to spawn a bunny here. + /// + private bool canspawnbunny; + + /// + /// Possible states of the button used for input, whether the spacebar, a VR controller trigger, etc. + /// public enum state { Idle, @@ -34,21 +79,19 @@ public enum state Press, Up }; - //The Buttons State - private state button; - public state Button { - get { - return button; - } - } + + /// + /// The current state of the button used for input. + /// + public state button { get; private set; } /// /// Awake is used to initialize any variables or game state before the game starts. /// void Awake() { - _canSpawnBunny = false; - trackedObj = GetComponent(); + canspawnbunny = false; + tracker = GetComponent(); zedPlane = FindObjectOfType(); bunnySpawner = GetComponent(); if (!leftCamera) @@ -58,13 +101,13 @@ void Awake() } /// - /// Sets a reference to the pointerBead. + /// Sets a reference to the placeholder object. Set from BunnySpawner.cs. /// - /// - public void SetPoinerBead(Transform _pointer) + /// The placeholder object. + public void SetPlaceholder(Transform pointer) { - pointerBead = _pointer; - pointLight = _pointer.GetChild(0).GetComponentInChildren(); + placeholder = pointer; + pointlight = pointer.GetChild(0).GetComponentInChildren(); } /// @@ -72,10 +115,9 @@ public void SetPoinerBead(Transform _pointer) /// Here we receive the input from the Controller. /// Then we decide what to do in each case. /// - private void Update() { - if (trackedObj == null) + if (tracker == null) { if (Input.GetKeyDown(KeyCode.Space)) button = state.Down; @@ -90,14 +132,14 @@ private void Update() { #if ZED_STEAM_VR //Check if a Controller tracked. - if ((int)trackedObj.index > 0) + if ((int)tracker.index > 0) { - device = SteamVR_Controller.Input((int)trackedObj.index); + device = SteamVR_Controller.Input((int)tracker.index); } //SteamVR provides OnButton responses for the Trigger input. - //When pressing Down, Holding it, or Releasing it. - if ((int)trackedObj.index > 0) + //When pressing down, holding it, or releasing it. + if ((int)tracker.index > 0) { if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger)) { @@ -178,12 +220,14 @@ private void Update() //It just got pressed. if (button == state.Down) { - //Enable the bunnySpawner to display the pointerBead. - bunnySpawner._canPlaceHolder = true; - //Hide the baseball. - if(bunnySpawner._baseballBat != null) - bunnySpawner._baseballBat.SetActive(false); - //Clear the list of detected planes by the Manager. + //Enable the bunnySpawner to display the placeholder. + bunnySpawner.canDisplayPlaceholder = true; + + //If we were holding the baseball bat but the user wants to re-place the bunny, hide the baseball bat. + if(bunnySpawner.baseballBat != null) + bunnySpawner.baseballBat.SetActive(false); + + //Clean up the list of detected planes. if (zedPlane.hitPlaneList.Count > 0) { for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) @@ -193,10 +237,10 @@ private void Update() } } //Destroy the current Bunny, if any, on the scene. - if (!bunnySpawner.canSpawnMoreBunnies && bunnySpawner._currentBunny != null) + if (!bunnySpawner.canSpawnMultipleBunnies && bunnySpawner.currentBunny != null) { - Destroy(bunnySpawner._currentBunny); - bunnySpawner._currentBunny = null; + Destroy(bunnySpawner.currentBunny); + bunnySpawner.currentBunny = null; } } @@ -205,22 +249,23 @@ private void Update() { if (zedPlane.hitPlaneList.Count == 0) { - //Launch the detection of Planes through the ZED Plane Detection Manager. - if (zedPlane.DetectPlaneAtHit(leftCamera.WorldToScreenPoint(pointerBead.position))) + //Start detecting planes through the ZED Plane Detection Manager. + if (zedPlane.DetectPlaneAtHit(leftCamera.WorldToScreenPoint(placeholder.position))) { //Get the normal of the plane. ZEDPlaneGameObject currentPlane = zedPlane.getHitPlane(zedPlane.hitPlaneList.Count - 1); Vector3 planeNormal = currentPlane.worldNormal; + //Check if the plane has a normal close enough to Y (horizontal surface) to be stable for the Bunny to spawn into. if (Vector3.Dot(planeNormal, Vector3.up) > 0.85f) { - //Allow to spawn the Bunny, and set the pointerBead to a positive color. - if (_canSpawnBunny == false) + //Allow spawning the Bunny, and set the placeholder to a positive color. + if (canspawnbunny == false) { - _canSpawnBunny = true; - bunnySpawner._placeHolderMat[0].mainTexture = goodPlacementTex[0]; - bunnySpawner._placeHolderMat[1].mainTexture = goodPlacementTex[1]; - pointLight.color = Color.blue; + canspawnbunny = true; + bunnySpawner.placeHolderMat[0].mainTexture = goodPlacementTex[0]; + bunnySpawner.placeHolderMat[1].mainTexture = goodPlacementTex[1]; + pointlight.color = Color.blue; } else //Clear the list of planes. { @@ -236,11 +281,12 @@ private void Update() } else //Surface wasn't horizontal enough { - //Don't allow for the Bunny to spawn, and set the pointerBead to a negative color. - _canSpawnBunny = false; - bunnySpawner._placeHolderMat[0].mainTexture = badPlacementTex[0]; - bunnySpawner._placeHolderMat[1].mainTexture = badPlacementTex[1]; - pointLight.color = Color.red; + //Don't allow the Bunny to spawn, and set the placeholder to a negative color. + canspawnbunny = false; + bunnySpawner.placeHolderMat[0].mainTexture = badPlacementTex[0]; + bunnySpawner.placeHolderMat[1].mainTexture = badPlacementTex[1]; + pointlight.color = Color.red; + //Clear the list of planes. for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { @@ -254,13 +300,13 @@ private void Update() else if (zedPlane.hitPlaneList.Count > 0) { - if (!Physics.Raycast(transform.position, pointerBead.position - transform.position)) + if (!Physics.Raycast(transform.position, placeholder.position - transform.position)) { - //Don't allow for the Bunny to spawn, and set the pointerBead to a negative color. - _canSpawnBunny = false; - bunnySpawner._placeHolderMat[0].mainTexture = badPlacementTex[0]; - bunnySpawner._placeHolderMat[1].mainTexture = badPlacementTex[1]; - pointLight.color = Color.red; + //Don't allow for the Bunny to spawn, and set the placeholder to a negative color. + canspawnbunny = false; + bunnySpawner.placeHolderMat[0].mainTexture = badPlacementTex[0]; + bunnySpawner.placeHolderMat[1].mainTexture = badPlacementTex[1]; + pointlight.color = Color.red; //Clear the list of planes. for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { @@ -275,9 +321,9 @@ private void Update() if (button == state.Up) { //If at that moment the bunny was allowed to spawn, proceed ot make the call. - if (_canSpawnBunny) + if (canspawnbunny) { - bunnySpawner.SpawnBunny(pointerBead.position); + bunnySpawner.SpawnBunny(placeholder.position); } else //Clear the list of planes. { @@ -287,9 +333,10 @@ private void Update() zedPlane.hitPlaneList.RemoveAt(i); } } + //Reset the booleans. - _canSpawnBunny = false; - bunnySpawner._canPlaceHolder = false; + canspawnbunny = false; + bunnySpawner.canDisplayPlaceholder = false; } } } diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnySpawner.cs b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnySpawner.cs index 6c1d7386..4061a1f1 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnySpawner.cs +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/BunnySpawner.cs @@ -3,71 +3,126 @@ using UnityEngine; using UnityEngine.UI; -public class BunnySpawner : MonoBehaviour { - - [Tooltip("Prefab of the Bunny that we're going to spawn.")] - public GameObject _bunnyPrefab; - [Tooltip("Prefab of the pointer which is a placeHolder that indicates if we can place or not a Bunny.")] - public GameObject _laserPointerPrefab; - //Reference to the object that holds the laser as an anchor. - private GameObject _laserPointerBeadHolder; - //Reference to the object that will be placed at the end of the laser. - private GameObject _pointerBead; - //Reference to the ZED's left camera gameobject. - private Camera _leftCamera; - [HideInInspector] //Boolean that decides if we can display the placeHolder bunny. - public bool _canPlaceHolder; - [Tooltip("Prefab of the UI that spawns when the Bunny collides with anything.")] - public GameObject _uiPrefab; - //The last UI spawned for a Bunny collision. - private GameObject _currentUI; - [HideInInspector] //The last Bunny gameObject spawned in the scene. - public GameObject _currentBunny; - //The text componenet of the current UI gameObject for displaying the score (Distance) of how far the Bunny was sent. - private Text _distanceText; - [HideInInspector] //The gameObject that holds the 3D Model of the Baseball Bat, so we can Show/Hide it. - public GameObject _baseballBat; - [Tooltip("The Material used on the placeHolder of the pointer Prefab.")] - public Material[] _placeHolderMat; - [Tooltip("The origin position for the Laser Pointer. If null, it takes this script's gameObject position.")] - public Transform _rayOrigin; - [Tooltip("Allow Multiple Bunnys to be spawn")] - public bool canSpawnMoreBunnies = false; - /// - /// Awake is used to initialize any variables or game state before the game starts. +/// +/// Moves around the placeholder object in the ZED place detection demo. +/// Also spawns the real object if BunnyPlacement.cs reports the placeholder is in a valid position. +/// +public class BunnySpawner : MonoBehaviour +{ + /// + /// Prefab of the Bunny object that we're going to spawn. + /// + [Tooltip("Prefab of the Bunny object that we're going to spawn.")] + public GameObject bunnyPrefab; + + /// + /// Prefab of the pointer/placeholder that indicates if we can place the object there or not. + /// + [Tooltip("Prefab of the pointer/placeholder that indicates if we can place the object there or not.")] + public GameObject pointerPrefab; + + /// + /// Prefab of the flag UI that spawns when the Bunny collides with anything. + /// + [Tooltip("Prefab of the flag UI that spawns when the Bunny collides with anything.")] + public GameObject uiPrefab; + + /// + /// The Material used on the placeHolder of the pointer prefab. Reference used to change colors based on placement validity. + /// + [Tooltip("The Material used on the placeholder of the pointer prefab. Reference used to change colors based on placement validity.")] + public Material[] placeHolderMat; + + /// + /// The origin position for the pointer, from which you aim the ray to check for a valid placement location. + /// If null (such as in the non-VR sample) it takes this script's GameObject position. + /// + [Tooltip("The origin position for the pointer, from which you aim the ray to check for a valid placement location. " + + "If null (such as in the non-VR sample) it takes this script's GameObject position.")] + public Transform rayOrigin; + + /// + /// Whether or not we can spawn multiple bunnies at once. + /// + [Tooltip("Whether or not we can spawn multiple bunnies at once.")] + public bool canSpawnMultipleBunnies = false; + + /// + /// Whether or not we can display the placeHolder bunny. + /// + [HideInInspector] + public bool canDisplayPlaceholder; + + /// + /// The last UI spawned for a Bunny collision. + /// + private GameObject currentui; + + /// + /// The last Bunny gameObject spawned in the scene. + /// + [HideInInspector] + public GameObject currentBunny; + + /// + /// Reference to the object that holds the laser as an anchor. + /// + private GameObject pointer; + + /// + /// Reference to the object that will be placed at the end of the laser. + /// + private GameObject placeholder; + + /// + /// Reference to the ZED's left camera gameobject. /// + private Camera leftcamera; + + /// + /// The text componenet of the current UI gameObject for displaying the score (Distance) of how far the Bunny was sent. + /// + private Text distancetext; + + /// + /// The gameObject that holds the 3D Model of the Baseball Bat, so we can Show/Hide it. + /// + [HideInInspector] + public GameObject baseballBat; + void Awake () { //Find the left camera object if we didn't assign it at start. - if (!_leftCamera) + if (!leftcamera) { - _leftCamera = ZEDManager.Instance.GetLeftCameraTransform().gameObject.GetComponent(); + leftcamera = ZEDManager.Instance.GetLeftCameraTransform().gameObject.GetComponent(); } - //Check if there is a Object Tracker on this object + //Check if there is a Object Tracker on this object for VR controls. var tracker = GetComponent(); if(tracker != null) { //Get the parent object of the baseball bat. if (transform.childCount > 1) { - _baseballBat = transform.GetChild(1).gameObject; - //Hide it. - _baseballBat.SetActive(false); + baseballBat = transform.GetChild(1).gameObject; + baseballBat.SetActive(false); //Hide it by default. It'll get revealed once we place a bunny. } } - //Instantiate the Laser Pointer Prefab and assign it to our variables. - if (_laserPointerPrefab != null) + //Instantiate the pointer prefab and assign it to our variables. + if (pointerPrefab != null) { - _laserPointerBeadHolder = Instantiate(_laserPointerPrefab) as GameObject; //Get the Anchor/root of the pointerBead. - _pointerBead = _laserPointerBeadHolder.transform.GetChild(0).gameObject; //Get the laser's pointerBead. + pointer = Instantiate(pointerPrefab) as GameObject; //Get the Anchor/root of the pointerBead. + placeholder = pointer.transform.GetChild(0).gameObject; //Get the laser's pointerBead. + } + //If we didn't set a transform for the pointer's origin position... + if (rayOrigin == null) + { + rayOrigin = transform; //...then take our local position. } - //If we didn't set a Transform for the laser's origin position... - if (_rayOrigin == null) - _rayOrigin = transform; //...then take our local position. - //Set the PlaneManager's reference to our pointerbead. - GetComponent().SetPoinerBead(_pointerBead.transform); + //Set the PlaneManager's reference to our placeholder. + GetComponent().SetPlaceholder(placeholder.transform); } /// @@ -77,118 +132,125 @@ void Awake () void FixedUpdate () { //Do we have a Pointer Bead to position in the world? - if (_laserPointerBeadHolder != null && GetComponent().Button != BunnyPlacement.state.Idle) + if (pointer != null && GetComponent().button != BunnyPlacement.state.Idle) { - Vector3 pointerBeadPoint; + Vector3 pointerposition; //Point the bead at the closest thing in front of the camera. - if (ZEDManager.Instance.IsZEDReady && FindPointerBeadPosition(out pointerBeadPoint) && _canPlaceHolder) + if (ZEDManager.Instance.IsZEDReady && FindPointerPosition(out pointerposition) && canDisplayPlaceholder) { //We hit something. Make sure the bead is active. - _laserPointerBeadHolder.SetActive(true); + pointer.SetActive(true); //Position the bead a the collision point, and make it face you. - _laserPointerBeadHolder.transform.position = pointerBeadPoint; - Quaternion rot = Quaternion.LookRotation(_leftCamera.transform.position - _laserPointerBeadHolder.transform.position); - _laserPointerBeadHolder.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); + pointer.transform.position = pointerposition; + Quaternion rot = Quaternion.LookRotation(leftcamera.transform.position - pointer.transform.position); + pointer.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); } else { //We didn't hit anything. Disable the bead object. - _laserPointerBeadHolder.SetActive(false); + pointer.SetActive(false); } } else - _laserPointerBeadHolder.SetActive(false); + pointer.SetActive(false); } /// /// Spawning the Bunny prefab. /// - /// + /// Where we'll spawn the bunny. public void SpawnBunny(Vector3 spawnPos) { //Instantiating the prefab. - GameObject newBunny = Instantiate(_bunnyPrefab, spawnPos, Quaternion.identity, null) as GameObject; + GameObject newBunny = Instantiate(bunnyPrefab, spawnPos, Quaternion.identity, null) as GameObject; //Make the UI to face the camera only on the Y axis. - Quaternion rot = Quaternion.LookRotation(_leftCamera.transform.position - spawnPos); + Quaternion rot = Quaternion.LookRotation(leftcamera.transform.position - spawnPos); newBunny.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); //Set this script as the BunnySpawner of the instantiated Bunny. newBunny.GetComponent().SetMySpawner(this); //Assigning it to the currentBunny variable. - _currentBunny = newBunny; + currentBunny = newBunny; //Start the coroutine that will enable/show the baseball bat. StartCoroutine(EnableBat()); } /// - /// Coroutine that waits for X seconds before doing something. + /// Waits for X seconds (to let the bunny fall into place) before activating the bat object. /// /// IEnumerator EnableBat() { //Wait for X seconds... yield return new WaitForSeconds(1f); - //then enable/show the baseball bat. - if(!_canPlaceHolder && _baseballBat != null) - _baseballBat.SetActive(true); + + //...then enable/show the baseball bat. + if (!canDisplayPlaceholder && baseballBat != null) + { + baseballBat.SetActive(true); //It's wabbit season. + } } /// - /// Instantiating the UI prefab. + /// Instantiating the flag UI prefab. /// /// public void SpawnUI(Vector3 spawnPos) { //Hide the baseball bat. - if(_baseballBat != null) - _baseballBat.SetActive(false); + if(baseballBat != null) + baseballBat.SetActive(false); + //Destroy the last UI that was spawned, if any. - if (_currentUI != null) + if (currentui != null) { - Destroy(_currentUI); - _currentUI = null; + Destroy(currentui); + currentui = null; } - //Instantiate a new UI gameObject. - GameObject newUI = Instantiate(_uiPrefab, null); - //Reposition the UI. + + //Instantiate a new UI GameObject and position it. + GameObject newUI = Instantiate(uiPrefab, null); newUI.transform.position = spawnPos; + //Make the UI to face the camera only on the Y axis. - Quaternion rot = Quaternion.LookRotation(_leftCamera.transform.position - spawnPos); + Quaternion rot = Quaternion.LookRotation(leftcamera.transform.position - spawnPos); newUI.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); - //Assigning the UI to the currentUI variable. - _currentUI = newUI; - //Assigning the UI's text component to the distanceText variable. - _distanceText = _currentUI.GetComponentInChildren(); - //Updating the distanceText value to the current Distance between the first/spawned position of the Bunny, and his current one. - _distanceText.text = Vector3.Distance(_currentBunny.GetComponent()._savedPos, spawnPos).ToString("F2") + " Meters"; + + //Configure the flag UI to be spawned. + currentui = newUI; + distancetext = currentui.GetComponentInChildren(); + + //Update the distanceText value to the current Distance between the first/spawned position of the Bunny, and his current one. + distancetext.text = Vector3.Distance(currentBunny.GetComponent().InitialPosition, spawnPos).ToString("F2") + " Meters"; + //If the UI position is higher than ours, and for a minimum of 1.5 meters, then rotate it 180 on the X axis so it's turned upside down. - if (_currentUI.transform.position.y > _leftCamera.transform.position.y && _currentUI.transform.position.y > 1.5f) + if (currentui.transform.position.y > leftcamera.transform.position.y && currentui.transform.position.y > 1.5f) { - _currentUI.transform.eulerAngles = new Vector3(180f, _currentUI.transform.rotation.eulerAngles.y, 0f); - _distanceText.transform.localEulerAngles = new Vector3(180f, 0f, 0f); + currentui.transform.eulerAngles = new Vector3(180f, currentui.transform.rotation.eulerAngles.y, 0f); + distancetext.transform.localEulerAngles = new Vector3(180f, 0f, 0f); } } /// - /// Tests the depth of the real world based on the laser origin position and rotation. + /// Tests the depth of the real world based on the pointer origin position and rotation. /// Returns the world position if it collided with anything. /// - /// - /// - bool FindPointerBeadPosition(out Vector3 pointerBeadPoint) + /// The world space position where the pointer is pointing. + /// True if a valid real world point was found. + bool FindPointerPosition(out Vector3 pointerbeadpoint) { //Find the distance to the real world. The bool will be false if there is an error reading the depth at the center of the screen. Vector3 realpoint; - bool foundrealdistance = ZEDSupportFunctions.HitTestOnRay(_leftCamera, _rayOrigin.position, _rayOrigin.rotation, 5.0f, 0.05f, out realpoint); + bool foundrealdistance = ZEDSupportFunctions.HitTestOnRay(leftcamera, rayOrigin.position, rayOrigin.rotation, 5.0f, 0.05f, out realpoint); //If we didn't find, return false so the laser and bead can be disabled. if (!foundrealdistance) { - pointerBeadPoint = Vector3.zero; + pointerbeadpoint = Vector3.zero; return false; } - else //send the world position of the collision. + else //Output the world position of the collision. { - pointerBeadPoint = realpoint; + pointerbeadpoint = realpoint; return true; } diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Capsule.cs b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Capsule.cs index a28c9891..b0276f26 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Capsule.cs +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/Capsule.cs @@ -1,19 +1,24 @@ using UnityEngine; + +/// +/// Creates a CapsuleFollower object that follows this one but that has proper physics simulation. +/// Used because VR controller movements don't allow for direct physics simulation. +/// In the ZED VR plane detection sample, this is attached to four parts of the baseball bat used to hit the bunny. +/// See CapsuleFollower.cs for more information. +/// public class Capsule : MonoBehaviour { - [SerializeField] - private CapsuleFollower _capsuleFollowerPrefab; - /// - /// Awake is used to initialize any variables or game state before the game starts. + /// CapsuleFollower script within a prefab that contains the script, a collider, and a rigidbody. /// + [SerializeField] + [Tooltip("CapsuleFollower script within a prefab that contains the script, a collider, and a rigidbody.")] + private CapsuleFollower capsulefollowerprefab; + private void Awake() { - //Instantiate the prefab. - var follower = Instantiate(_capsuleFollowerPrefab); - //Set it to this object's position. - follower.transform.position = transform.position; - //Assign itself to its target to follow. - follower.SetFollowTarget(this); + var follower = Instantiate(capsulefollowerprefab); //Instantiate the prefab. + follower.transform.position = transform.position; //Set it to this object's position. + follower.SetFollowTarget(this); //Assign this as its target to follow. } } \ No newline at end of file diff --git a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/CapsuleFollower.cs b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/CapsuleFollower.cs index 0e0affc8..162c381c 100644 --- a/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/CapsuleFollower.cs +++ b/ZEDCamera/Assets/ZED/Examples/Plane Detection/Scripts/CapsuleFollower.cs @@ -1,35 +1,63 @@ using UnityEngine; +/// +/// Follows a given Capsule object. Used because VR controller movements don't allow for direct physics simulation. +/// Instead, we apply phyics forces by script to make separate capsule colliders follow that controller, +/// which then apply their forces to objects that this object would normally hit. +/// This script is attached to those follower objects. The object being followed has the Capsule component. +/// Used in the ZED VR plane detection sample for the baseball bat. +/// public class CapsuleFollower : MonoBehaviour { - private Capsule _target; - private Rigidbody _rigidbody; - private Vector3 _velocity; - private Collider _collider; + /// + /// Object this capsule will follow. + /// + private Capsule target; + + /// + /// Rigidbody attached to this object. + /// + private Rigidbody rb; + + /// + /// The velocity the rigidbody needs to be set to. Used so we can update the target velocity + /// in Update() but apply to the rigidbody in FixedUpdate() (which is where physics is actually run). + /// + private Vector3 velocity; + + /// + /// The collider attached to this object. + /// + private Collider capsulecollider; + + /// + /// Multiplier used to govern how quickly this follower follows its target when it moves. + /// Higher values will make it lag behind less but may cause it to overshoot. + /// [SerializeField] - private float _sensitivity = 50; + private float sensitivity = 50; /// - /// Awake is used to initialize any variables or game state before the game starts. + /// Awake is used to initialize any variables or game states before the game starts. /// private void Awake() { - _rigidbody = GetComponent(); - _collider = GetComponent(); + rb = GetComponent(); + capsulecollider = GetComponent(); } /// /// Update is called every frame. - /// Here we enable.disable the collider whenever baseball bat is active or not. + /// Here we enable/disable the collider whenever baseball bat is active or not. /// private void Update() { - if (_target.transform.parent.gameObject.activeInHierarchy) + if (target.transform.parent.gameObject.activeInHierarchy) { - _collider.enabled = true; + capsulecollider.enabled = true; } else - _collider.enabled = false; + capsulecollider.enabled = false; } /// @@ -38,16 +66,17 @@ private void Update() /// private void FixedUpdate() { - Vector3 destination = _target.transform.position; - _rigidbody.transform.rotation = _target.transform.rotation; + Vector3 destination = target.transform.position; + rb.transform.rotation = target.transform.rotation; - _velocity = (destination - _rigidbody.transform.position) * _sensitivity; + velocity = (destination - rb.transform.position) * sensitivity; - _rigidbody.velocity = _velocity; + rb.velocity = velocity; } /// - /// When another collider enters ours, we assign our rigidbody's velocity to his. + /// When another collider enters ours, we assign our rigidbody's velocity to its + /// In the ZED VR plane detection sample, this is how the bunny gets launched. . /// /// private void OnTriggerEnter(Collider other) @@ -56,31 +85,32 @@ private void OnTriggerEnter(Collider other) //Checking if its a Bunny, with a Rigidbody and that is not moving. if (colBunny != null) { - if (other.GetComponent() && !colBunny._moving) + if (other.GetComponent() && !colBunny.IsMoving) { - if (_rigidbody.velocity.y <= -2) + if (rb.velocity.y <= -2) { colBunny.anim.SetTrigger("Squeeze"); colBunny.GetHit(hit: false); } - else if (_rigidbody.velocity.magnitude > 2f) + else if (rb.velocity.magnitude > 2f) { //Send a call to GetHit() which delays for X seconds the Bunny's detection with the real world. //Since the Bunny is already on the floor, it might return true for collision the moment the baseball bat touches it. colBunny.GetHit(hit: true); - //Assign our velocity with some changes. I found that it feels better when it's half the force. - other.GetComponent().velocity = _rigidbody.velocity / 2; + + //Assign our velocity with some changes. Halving the velocity makes it feel more natural when hitting the bunny. + other.GetComponent().velocity = rb.velocity / 2; } } } } /// - /// Sets the target to follow. + /// Sets the target to follow. Called by Capsule. /// - /// + /// public void SetFollowTarget(Capsule myTarget) { - _target = myTarget; + target = myTarget; } } \ No newline at end of file diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scene/Planetarium.unity b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scene/Planetarium.unity index dd2a1636..45dd725c 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scene/Planetarium.unity +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scene/Planetarium.unity @@ -77,15 +77,17 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVRFiltering: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousColorSigma: 1 - m_PVRFilteringAtrousNormalSigma: 1 - m_PVRFilteringAtrousPositionSigma: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -163,6 +165,28 @@ Prefab: propertyPath: target value: objectReference: {fileID: 915697319} + - target: {fileID: 114219090854195206, guid: dda0baf117c99c04dbb8fb1c9e2d1c69, + type: 2} + propertyPath: offset + value: 0.05 + objectReference: {fileID: 0} + - target: {fileID: 4032380963270518, guid: dda0baf117c99c04dbb8fb1c9e2d1c69, type: 2} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4032380963270518, guid: dda0baf117c99c04dbb8fb1c9e2d1c69, type: 2} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4032380963270518, guid: dda0baf117c99c04dbb8fb1c9e2d1c69, type: 2} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 114258083924026048, guid: dda0baf117c99c04dbb8fb1c9e2d1c69, + type: 2} + propertyPath: RotationSpeed + value: 0.1 + objectReference: {fileID: 0} m_RemovedComponents: [] m_ParentPrefab: {fileID: 100100000, guid: dda0baf117c99c04dbb8fb1c9e2d1c69, type: 2} m_IsPrefabParent: 0 @@ -245,8 +269,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 454b1f0b0de2bb644a283d964ccf7f06, type: 3} m_Name: m_EditorClassIdentifier: + index: -1 deviceToTrack: 1 - _latencyCompensation: 78 + latencyCompensation: 78 + SNHolder: --- !u!4 &1227702868 Transform: m_ObjectHideFlags: 0 @@ -287,8 +313,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 454b1f0b0de2bb644a283d964ccf7f06, type: 3} m_Name: m_EditorClassIdentifier: + index: -1 deviceToTrack: 0 - _latencyCompensation: 78 + latencyCompensation: 78 + SNHolder: --- !u!4 &1926151454 Transform: m_ObjectHideFlags: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/AsteroidsManager.cs b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/AsteroidsManager.cs index b8ea9d90..313067d7 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/AsteroidsManager.cs +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/AsteroidsManager.cs @@ -2,35 +2,99 @@ using System.Collections.Generic; using UnityEngine; +/// +/// Used in the ZED planetarium sample to draw asteroids in the solar system's asteroid belt and rotate them. +/// The asteroids are not instantiated as GameObjects, but drawn each frame with DrawMeshInstanced. +/// Given there are many asteroids to draw, this reduces draw calls substantially along with some CPU overhead. +/// public class AsteroidsManager : MonoBehaviour { - + /// + /// Prefab containing the first asteroid mesh type. + /// + [Tooltip("Prefab containing the first asteroid mesh type.")] public GameObject asteroidsType1; + + /// + /// Prefab containing the first asteroid mesh type. + /// + [Tooltip("Prefab containing the first asteroid mesh type.")] public GameObject asteroidsType2; - public Transform center; + + /// + /// How many asteroids of each type to draw. (There will be twice this number of asteroids in total). + /// + [Tooltip("How many asteroids of each type to draw. (There will be twice this number of asteroids in total).")] public static int amount = 100; + + /// + /// The radius of the asteroid belt. This is meters when the localscale of this object is 1,1,1. + /// + [Tooltip("The radius of the asteroid belt. This is meters when the localscale of this object is 1,1,1. ")] public float radius = 1; - public float offset = 0.0f; + + /// + /// How wide the asteroids can be spaced apart. Values too low or high may cause asteroids to intersect Mars or Jupiter. + /// + [Tooltip("How wide the asteroids can be spaced apart. Values too low or high may cause asteroids to intersect Mars or Jupiter. ")] + public float offset = 0.05f; + + /// + /// Holds the transform of where the asteroid started when it was created (for asteroid type 1). + /// Matrix4x4[] listPositionsOrigin = new Matrix4x4[amount]; + + /// + /// Holds the current transforms of the type 1 asteroids, updated each frame based on the solar system's location and its orbit. + /// Matrix4x4[] listPositions = new Matrix4x4[amount]; + /// + /// Holds the transform of where the asteroid started when it was created (for asteroid type 1). + /// Matrix4x4[] listPositionsOrigin2 = new Matrix4x4[amount]; + + /// + /// Holds the current transforms of the type 2 asteroids, updated each frame based on the solar system's location and its orbit. + /// Matrix4x4[] listPositions2 = new Matrix4x4[amount]; - public ZEDManager manager; + + /// + /// The scene's ZEDManager object. + /// + private ZEDManager manager; + + /// + /// The left Camera component in the ZED rig. + /// private Camera leftCamera = null; + /// + /// The right Camera component in the ZED rig, if applicable (ie. when using the stereo rig). + /// private Camera rightCamera = null; + + void Start() { - CreateAsteroids(listPositionsOrigin, listPositions, amount, radius, offset); - CreateAsteroids(listPositionsOrigin2, listPositions2, amount, radius, offset); + if(!manager) + { + manager = ZEDManager.Instance; + } + + CreateAsteroids(listPositionsOrigin, amount, radius, offset); //Create all type 1 asteroids. + CreateAsteroids(listPositionsOrigin2, amount, radius, offset); //Create all type 2 asteroids. } - private void CreateAsteroids(Matrix4x4[] listPositionsOrigin, Matrix4x4[] listPositions, int amount, float radius, float offset) + /// + /// Fills the first Matrix array with the origin positions and scales of randomly positioned asteroids. + /// + /// Array to be populated with matrixes of each asteroid's starting transform. + /// How many asteroids to make. + /// Radius of the asteroid belt/ + /// How far each asteroid can randomly deviate from the radius. + private void CreateAsteroids(Matrix4x4[] listPositionsOrigin, int amount, float radius, float offset) { - // Matrix4x4 m2 = Matrix4x4.TRS(center.position, Quaternion.identity, Vector3.one); - // - // listPositionsOrigin.Add(m2); for (int i = 0; i < amount; ++i) { // 1. translation: displace along circle with 'radius' in range [-offset, offset] @@ -50,7 +114,6 @@ private void CreateAsteroids(Matrix4x4[] listPositionsOrigin, Matrix4x4[] listPo // 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector float rotAngle = (Random.Range(0, 100000) % 360); - //Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.identity, new Vector3(scale, scale, scale)); Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.Euler(rotAngle, rotAngle, rotAngle), new Vector3(scale, scale, scale)); @@ -59,7 +122,11 @@ private void CreateAsteroids(Matrix4x4[] listPositionsOrigin, Matrix4x4[] listPo } - + /// + /// Called each frame to move, rotate and scale the asteroids based on this object's transform and their orbit. + /// + /// All asteroids' initial matrixes. + /// All asteroids' current matrixes. void UpdatePosition(Matrix4x4[] listPositionsOrigin, Matrix4x4[] listPositions) { for (int i = 0; i < listPositionsOrigin.Length; ++i) diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/LookAtCamera.cs b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/LookAtCamera.cs index 6321a3a2..a29adc99 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/LookAtCamera.cs +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/LookAtCamera.cs @@ -2,16 +2,52 @@ using System.Collections.Generic; using UnityEngine; -public class LookAtCamera : MonoBehaviour { - +/// +/// Makes the GameObject turn to face the target object each frame. +/// Used for an outline effect on the ZED planetarium sample's sun, as it's drawn by a quad. +/// +public class LookAtCamera : MonoBehaviour +{ + /// + /// The target transform/object to face. + /// + [Tooltip("The target transform/object to face.")] public Transform target; + + /// + /// True if this object and the target object do *not* have the same position. + /// The script will only look at the target when true. + /// Otherwise, Quaternion.LookRotation will spam console errors. + /// bool canLook = false; - void Update () { - if(!canLook && transform.position - target.position != Vector3.zero) + private void Start() + { + if(!target) //If we didn't set the target object, try to find the best object for it. + { + target = GameObject.Find("Camera_eyes").transform; //Try the center object on the ZED stereo rig. + if (!target) + { + target = ZEDManager.Instance.GetLeftCameraTransform(); //Try the ZED's left eye. Works for the ZED mono rig. + } + if(!target) + { + target = Camera.main.transform; //If no ZED rig is availables, use the main camera. + } + } + } + + void Update () + { + //Make sure the target and this object don't have the same position. + if (!canLook && transform.position - target.position != Vector3.zero) + { canLook = true; + } - if(canLook) - transform.rotation = Quaternion.LookRotation(transform.position - target.position); + if (canLook) + { + transform.rotation = Quaternion.LookRotation(transform.position - target.position); + } } } diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetMover.cs b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetMover.cs index 7bed9e86..2731edf7 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetMover.cs +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetMover.cs @@ -3,33 +3,52 @@ using UnityEngine; using UnityEngine.Networking; -public class PlanetMover : MonoBehaviour { - +/// +/// Rotates this object around the specified center transform, as well as around itself on the specified axis. +/// Used in the ZED planetarium sample on each planet/moon to make it orbit the sun and also spin on its own axis. +/// +public class PlanetMover : MonoBehaviour +{ + /// + /// The transform this object revolves around. Always the Sun in the ZED planetarium sample, except for the moon. + /// + [Tooltip("The transform this object revolves around. Always the Sun in the ZED planetarium sample, except for the moon.")] public Transform center; + + /// + /// Degrees per second this object moves around its orbit. + /// + [Tooltip("Degrees per second this object moves around its orbit.")] public float speedRevolution = 10; + /// + /// The axis of rotation around its poles, ie, the direction from the planet's south pole to the north pole. + /// + [Tooltip("The axis of rotation around its poles, ie, the direction from the planet's south pole to the north pole. ")] public Vector3 axis = Vector3.up; - public float speed = 10.0f; - private Vector3 dir; - private Vector3 originPos; + /// + /// Degrees per second the object rotates on its own axis. + /// + [Tooltip("Degrees per second the object rotates on its own axis. ")] + public float speed = 10.0f; - private void OnEnable() - { - //originPos = transform.localPosition; - } + /// + /// Axis the planet revolves around on its orbit. + /// + private Vector3 dir; private void Start() { - dir = center.up; + dir = center.up; //Get the axis of rotation from the object we're rotating. } // Update is called once per frame void Update () { - transform.RotateAround(center.position, center.TransformDirection(dir), Time.deltaTime * speedRevolution); + transform.RotateAround(center.position, center.TransformDirection(dir), Time.deltaTime * speedRevolution); //Rotating around the sun (orbit). - transform.Rotate(axis, speed*Time.deltaTime, Space.Self); + transform.Rotate(axis, speed*Time.deltaTime, Space.Self); //Rotating around its own axis (night/day). } } diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetariumMover.cs b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetariumMover.cs index 6cb0e617..dfc38638 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetariumMover.cs +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/PlanetariumMover.cs @@ -8,34 +8,98 @@ //#define __ENABLE__SOUND__ +/// +/// Lets the user move, rotate and scale the planetarium object in the ZED planetarium sample scene. +/// Also makes sure that relevant fields not tied directly to a transform, like sound distance and light radius, +/// get properly scaled with the planetarium itself. +/// public class PlanetariumMover : MonoBehaviour { - + /// + /// How fast the solar system changes size when scaled. + /// + [Tooltip("How fast the solar system changes size when scaled. ")] public float speedGrowth = 1.0f; + + /// + /// How quickly the solar system moves up, right, forward, etc. + /// + [Tooltip("How quickly the solar system moves up, right, forward, etc. ")] public float speedMove = 1.0f; + + /// + /// How quickly the solar system rotates on the Y axis when the user rotates it (unrelated to planet orbits). + /// + [Tooltip("How quickly the solar system rotates on the Y axis when the user rotates it (unrelated to planet orbits). ")] public float speedRotation = 20.0f; - private ZEDManager manager; + /// + /// The Planetarium object being governed. This is the 'Planetarium' GameObject in the ZED planetarium scene. + /// + [Tooltip("The Planetarium object being governed. This is the 'Planetarium' GameObject in the ZED planetarium scene.")] public GameObject planetarium; - private Light sunLight; - private GameObject sunContainer; - private float currentScale; + //public static bool scaling = false; - private float currentLighRange = 1; - private float currentLightRangeSunSpot = 1; - private float currentLightRangeSunHalo = 0.6f; + /// + /// The scene's ZEDManager component. + /// + private ZEDManager manager; - private const float MAX_LIMIT_SCALE = 3.0f; - private const float MIN_LIMIT_SCALE = 0.05f; + /// + /// The Sun GameObject. + /// + private GameObject suncontainer; + /// + /// Light component on the Sun GameObject. + /// + private Light sunlight; - public static bool scaling = false; + /// + /// Light component on the SunSpotLight GameObject. + /// private Light spotLightSun; - private Light pointLightSun; //for Halo + /// + /// Light component on the SunHaloLight GameObject. + /// + private Light halolightsun; //for Halo + + /// + /// The current scale setting. Equal to transform.scale.x, which is used as a proxy for all three values. + /// + private float currentscale; + + /// + /// The range of the sunlight Light component. + /// + private float currentlightrange = 1; + + /// + /// The range of the SunSpotLight's Light component. + /// + private float currentlightrangesunspot = 1; + + /// + /// The range of the SunHaloLight's Light component. + /// + private float currentlightrangesunhalo = 0.6f; + + /// + /// The largest you can scale the planetarium. + /// + private const float MAX_LIMIT_SCALE = 3.0f; + + /// + /// The smallest you can scale the planetarium. + /// + private const float MIN_LIMIT_SCALE = 0.05f; - private float scaler = 5; + /// + /// When scaling the planetarium, the amount changed each frame is divided by this number. + /// + private float scaler = 5; @@ -49,41 +113,29 @@ public class PlanetariumMover : MonoBehaviour void Start() { - planetarium = GameObject.Find("Planetarium"); - currentScale = planetarium.transform.localScale.x; - sunContainer = planetarium.transform.Find("Sun").gameObject; - sunLight = sunContainer.GetComponent(); - + if (!planetarium) + { + planetarium = GameObject.Find("Planetarium"); + } + currentscale = planetarium.transform.localScale.x; + suncontainer = planetarium.transform.Find("Sun").gameObject; + sunlight = suncontainer.GetComponent(); + currentlightrange = sunlight.range * (1 / currentscale); - currentLighRange = sunLight.range * (1 / currentScale); - if (manager == null) - { - GameObject m = GameObject.Find("ZED_Rig_Stereo"); - if(m == null) - m = GameObject.Find("ZED_Rig_Mono"); - if(m == null) - m = GameObject.Find("ZED_GreenScreen"); - - if (m != null) - manager = m.GetComponent (); - else - manager = null; - } - spotLightSun = sunContainer.transform.Find("SunSpotLight").GetComponent(); - pointLightSun = sunContainer.transform.Find("SunHaloLight").GetComponent(); + manager = ZEDManager.Instance; + + spotLightSun = suncontainer.transform.Find("SunSpotLight").GetComponent(); + halolightsun = suncontainer.transform.Find("SunHaloLight").GetComponent(); - currentLightRangeSunSpot = spotLightSun.range*(1/currentScale); - currentLightRangeSunHalo = pointLightSun.range*(1/currentScale); + currentlightrangesunspot = spotLightSun.range * (1 / currentscale); + currentlightrangesunhalo = halolightsun.range * (1 / currentscale); #if __ENABLE__SOUND__ currentMaxSoundDistanceJupiter = jupiterSound.maxDistance * (1 / currentScale); currentMaxSoundDistanceSun = sunSound.maxDistance * (1 / currentScale); #endif - - - } private void OnEnable() @@ -97,103 +149,110 @@ private void OnDisable() } + /// + /// Called when the ZED is finished initializing, using the ZEDManager.OnZEDReady callback. + /// void ZEDReady() { - if (manager) planetarium.transform.position = manager.OriginPosition + manager.OriginRotation * Vector3.forward; + planetarium.transform.position = manager.OriginPosition + manager.OriginRotation * Vector3.forward; } // Update is called once per frame void Update() { - string [] names = Input.GetJoystickNames(); - bool hasJoystick = false; - - if (names.Length>0) - hasJoystick = names[0].Length > 0; - - - /// Adjust Planetarium X/Y/Z position - float axisH = Input.GetAxis("Horizontal"); - float axisV = Input.GetAxis("Vertical"); - - Quaternion gravity = Quaternion.identity; - - if (manager) { - gravity = Quaternion.FromToRotation (manager.GetZedRootTansform ().up, Vector3.up); - planetarium.transform.localPosition += manager.GetLeftCameraTransform ().right * axisH * speedMove * Time.deltaTime; - planetarium.transform.localPosition += gravity * manager.GetLeftCameraTransform ().forward * axisV * speedMove * Time.deltaTime; - } - - /// Adjust Scale of Virtual objects,lights, sounds - bool ScaleUpButton = Input.GetButton("Fire1") || Input.GetKey (KeyCode.JoystickButton5) || (Input.GetAxis("Fire1")>=1); - bool ScaleDownButton = Input.GetButton ("Fire2") || (Input.GetAxis ("Fire2") >= 1); - - currentScale += System.Convert.ToInt32(ScaleUpButton) * speedGrowth * Time.deltaTime / scaler; - currentScale -= System.Convert.ToInt32(ScaleDownButton) * speedGrowth * Time.deltaTime / scaler; - if (currentScale < MIN_LIMIT_SCALE) currentScale = MIN_LIMIT_SCALE; - if (currentScale > MAX_LIMIT_SCALE) currentScale = MAX_LIMIT_SCALE; - planetarium.transform.localScale = new Vector3(currentScale, currentScale, currentScale); - sunLight.range = currentLighRange * currentScale; - spotLightSun.range = currentLightRangeSunSpot * currentScale; - pointLightSun.range = currentLightRangeSunHalo * currentScale; - - #if __ENABLE__SOUND__ + string[] names = Input.GetJoystickNames(); + bool hasJoystick = false; + + if (names.Length > 0) + hasJoystick = names[0].Length > 0; + + + /// Adjust Planetarium X/Y/Z position + float axisH = Input.GetAxis("Horizontal"); + float axisV = Input.GetAxis("Vertical"); + + Quaternion gravity = Quaternion.identity; + + gravity = Quaternion.FromToRotation(manager.GetZedRootTansform().up, Vector3.up); + planetarium.transform.localPosition += manager.GetLeftCameraTransform().right * axisH * speedMove * Time.deltaTime; + planetarium.transform.localPosition += gravity * manager.GetLeftCameraTransform().forward * axisV * speedMove * Time.deltaTime; + + /// Adjust Scale of Virtual objects,lights, sounds + bool ScaleUpButton = Input.GetButton("Fire1") || Input.GetKey(KeyCode.JoystickButton5) || (Input.GetAxis("Fire1") >= 1); + bool ScaleDownButton = Input.GetButton("Fire2") || (Input.GetAxis("Fire2") >= 1); + + currentscale += System.Convert.ToInt32(ScaleUpButton) * speedGrowth * Time.deltaTime / scaler; + currentscale -= System.Convert.ToInt32(ScaleDownButton) * speedGrowth * Time.deltaTime / scaler; + if (currentscale < MIN_LIMIT_SCALE) currentscale = MIN_LIMIT_SCALE; + if (currentscale > MAX_LIMIT_SCALE) currentscale = MAX_LIMIT_SCALE; + planetarium.transform.localScale = new Vector3(currentscale, currentscale, currentscale); + sunlight.range = currentlightrange * currentscale; + spotLightSun.range = currentlightrangesunspot * currentscale; + halolightsun.range = currentlightrangesunhalo * currentscale; + +#if __ENABLE__SOUND__ jupiterSound.maxDistance = currentMaxSoundDistanceJupiter * currentScale; sunSound.maxDistance = currentMaxSoundDistanceSun * currentScale; - #endif +#endif + + /// Adjust Rotation of Planetarium + if (CheckAxes("DPad X") && hasJoystick) + { + float axisX = Input.GetAxis("DPad X"); //multiply by 10 since sensibility is at 0.1 by default + planetarium.transform.Rotate(gravity * manager.GetLeftCameraTransform().up * axisX * speedRotation, Space.World); + } + else + { + float axisX = System.Convert.ToInt32(Input.GetKey(KeyCode.R)); + planetarium.transform.Rotate(gravity * manager.GetLeftCameraTransform().up * axisX * speedRotation, Space.World); + } - /// Adjust Rotation of Planetarium - if (CheckAxes ("DPad X") && hasJoystick) { - float axisX = Input.GetAxis ("DPad X"); //multiply by 10 since sensibility is at 0.1 by default - if (manager) planetarium.transform.Rotate (gravity * manager.GetLeftCameraTransform ().up * axisX * speedRotation, Space.World); - } else { - float axisX = System.Convert.ToInt32(Input.GetKey (KeyCode.R)); - if (manager) planetarium.transform.Rotate (gravity * manager.GetLeftCameraTransform ().up * axisX * speedRotation, Space.World); - } + //adjust Height of Planetarium + if (CheckAxes("DPad Y") && hasJoystick) + { + float axisY = Input.GetAxis("DPad Y"); + planetarium.transform.localPosition += gravity * manager.GetLeftCameraTransform().up * axisY * speedMove * Time.deltaTime; + } + else + { + float axisY = System.Convert.ToInt32(Input.GetKey(KeyCode.PageUp)) - System.Convert.ToInt32(Input.GetKey(KeyCode.PageDown)); + planetarium.transform.localPosition += gravity * manager.GetLeftCameraTransform().up * axisY * speedMove * Time.deltaTime; + } - //adjust Height of Planetarium - if (CheckAxes ("DPad Y") && hasJoystick) { - float axisY = Input.GetAxis ("DPad Y"); - if (manager) planetarium.transform.localPosition += gravity * manager.GetLeftCameraTransform ().up * axisY * speedMove * Time.deltaTime; - } else { - float axisY = System.Convert.ToInt32(Input.GetKey (KeyCode.PageUp)) - System.Convert.ToInt32(Input.GetKey(KeyCode.PageDown)); - if (manager) planetarium.transform.localPosition += gravity * manager.GetLeftCameraTransform ().up * axisY * speedMove * Time.deltaTime; - } - } - - public static bool CheckAxes(string choice) - { + + public static bool CheckAxes(string choice) + { #if UNITY_EDITOR - var inputManager = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset")[0]; - - SerializedObject obj = new SerializedObject(inputManager); - - SerializedProperty axisArray = obj.FindProperty("m_Axes"); - - if (axisArray.arraySize == 0) - Debug.Log("No Axes"); - - for( int i = 0; i < axisArray.arraySize; ++i ) - { - var axis = axisArray.GetArrayElementAtIndex(i); - var name = axis.FindPropertyRelative("m_Name").stringValue; - if (name == choice) - return true; - - } - - - return false; + var inputManager = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset")[0]; + + SerializedObject obj = new SerializedObject(inputManager); + + SerializedProperty axisArray = obj.FindProperty("m_Axes"); + + if (axisArray.arraySize == 0) + Debug.Log("No Axes"); + + for (int i = 0; i < axisArray.arraySize; ++i) + { + var axis = axisArray.GetArrayElementAtIndex(i); + var name = axis.FindPropertyRelative("m_Name").stringValue; + if (name == choice) + return true; + + } + + + return false; #else return true; #endif - } + } } diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunBursts.cs b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunBursts.cs index e07c1b54..76953787 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunBursts.cs +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunBursts.cs @@ -2,16 +2,25 @@ using System.Collections.Generic; using UnityEngine; -public class SunBursts : MonoBehaviour { - +/// +/// Switches on all objects in its list slowly, pausing two seconds on each one. +/// Used in the ZED planetarium sample to stagger the animations of the 18 SunBurstRoot objects on the sun. +/// +public class SunBursts : MonoBehaviour +{ + /// + /// All objects to be turned on, in order. Script assumes they begin disabled. + /// + [Tooltip("All objects to be turned on, in order. Script assumes they begin disabled.")] public List sunBurstsGO = new List(); - // Use this for initialization - IEnumerator Start () { + // Use this for initialization + IEnumerator Start () + { for (int i = 0; i < sunBurstsGO.Count; i++) { yield return new WaitForSeconds(2f); sunBurstsGO[i].SetActive(true); } } -} +} \ No newline at end of file diff --git a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunCorona.cs b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunCorona.cs index 0bc286cf..0017a91b 100644 --- a/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunCorona.cs +++ b/ZEDCamera/Assets/ZED/Examples/Planetarium/Scripts/SunCorona.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using UnityEngine; -public class SunCorona : MonoBehaviour { +public class SunCorona : MonoBehaviour +{ Material mat; Vector2 offset; diff --git a/ZEDCamera/Assets/ZED/Examples/SimpleMR/Scenes/SimpleMR.unity b/ZEDCamera/Assets/ZED/Examples/SimpleMR/Scenes/SimpleMR.unity index ba9d67ef..fae438ec 100644 --- a/ZEDCamera/Assets/ZED/Examples/SimpleMR/Scenes/SimpleMR.unity +++ b/ZEDCamera/Assets/ZED/Examples/SimpleMR/Scenes/SimpleMR.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 1928171912} - m_IndirectSpecularColor: {r: 0.4366757, g: 0.48427194, b: 0.5645252, a: 1} + m_IndirectSpecularColor: {r: 0.17276844, g: 0.21589246, b: 0.2978263, a: 1} --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 @@ -78,15 +78,17 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVRFiltering: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousColorSigma: 1 - m_PVRFilteringAtrousNormalSigma: 1 - m_PVRFilteringAtrousPositionSigma: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -1286,6 +1288,11 @@ Prefab: propertyPath: renderingPath value: 3 objectReference: {fileID: 0} + - target: {fileID: 114491592745282986, guid: 76db3eb81fd21ae45bab5204e324ae42, + type: 2} + propertyPath: postProcessing + value: 0 + objectReference: {fileID: 0} m_RemovedComponents: [] m_ParentPrefab: {fileID: 100100000, guid: 76db3eb81fd21ae45bab5204e324ae42, type: 2} m_IsPrefabParent: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scenes/SpatialMapping.unity b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scenes/SpatialMapping.unity index 5e7295df..f5c8fefa 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scenes/SpatialMapping.unity +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scenes/SpatialMapping.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.4366757, g: 0.48427194, b: 0.5645252, a: 1} + m_IndirectSpecularColor: {r: 0.17276844, g: 0.21589246, b: 0.2978263, a: 1} --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallLauncher.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallLauncher.cs index a7e6a6b8..cf9cf0dc 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallLauncher.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallLauncher.cs @@ -6,63 +6,70 @@ /// -/// Creates multiple balls with a physic materials and launch them +/// Creates multiple balls with physics materials and launch them. /// public class BallLauncher : MonoBehaviour { /// - /// Model of the projectile + /// Prefab object to be launched. /// + [Tooltip("Prefab object to be launched.")] public GameObject projectile; /// - /// list of all the projectiles + /// Array of all previously-instantiated projectiles, so we can reuse them and prevent too many from appearing (similar to a queue). /// + [Tooltip("Array of all previously-instantiated projectiles, so we can reuse them and prevent too many from appearing (similar to a queue).")] private GameObject[] projectiles; /// - /// Launch intensity for the init velocity of the ball + /// Launch intensity for the init velocity of the ball. /// + [Tooltip("Launch intensity for the init velocity of the ball.")] public int LaunchIntensity = 750; /// - /// Number of spheres max + /// Maximum number of spheres that can be instantiated at once. /// private const int SPHERE_NB = 100; /// - /// Distance max betwween the user and the speher before the sphere is disabled + /// Distance max between the user and the sphere before the sphere is disabled. /// private const int DISTANCE_MAX = 50; /// - /// Time max a sphere can be alived before disabling the sphere + /// Maximum time a sphere can be alive before it gets disabled. /// private const int TIME_MAX = 30; /// - /// Colors of the balls + /// Colors of the balls. /// - private Color[] ballColors; + private Color[] ballcolors; /// - /// Times for each sphere + /// How long each sphere has been around. /// private float[] times; /// - /// Id of the next sphere to launch + /// ID of the next sphere to launch. /// - private int countSphere = 0; + private int countsphere = 0; /// - /// Timer between the throwing of balls + /// Cooldown period between launching balls. /// - private float timeBallMax = 0.05f; - private float timerBall = 0.0f; + private float timeballmax = 0.05f; /// - /// Offset of the launcher + /// The actual timer incremented each frame after firing a ball, then resetting once timeballmax is hit. + /// + private float timerball = 0.0f; + + /// + /// Offset of the launcher from the transform. /// private Vector3 offset = new Vector3(0.1f, -0.1f, 0.0f); @@ -78,10 +85,10 @@ void Start() launcher.hideFlags = HideFlags.HideAndDontSave; launcher.transform.parent = transform; launcher.transform.localPosition = offset; - ballColors = new Color[10]; + ballcolors = new Color[10]; for (int i = 0; i < 10; i++) { - ballColors[i] = Color.HSVToRGB(0.1f * i, 0.8f, 1.0f); + ballcolors[i] = Color.HSVToRGB(0.1f * i, 0.8f, 1.0f); } projectiles = new GameObject[SPHERE_NB]; times = new float[SPHERE_NB]; @@ -92,9 +99,9 @@ void Start() { projectiles[i] = Instantiate(projectile, launcher.transform.position, launcher.transform.rotation); projectiles[i].transform.localScale = new Vector3(0.10f, 0.10f, 0.10f); - projectiles[i].GetComponent().material.color = ballColors[count]; + projectiles[i].GetComponent().material.color = ballcolors[count]; Light l = projectiles[i].AddComponent(); - l.color = ballColors[count]; + l.color = ballcolors[count]; l.intensity = 2; l.range = 1.0f; projectiles[i].AddComponent(); @@ -132,32 +139,32 @@ void Update() if (ready && (Input.GetKey(KeyCode.Space) || Input.GetButton("Fire1"))) { - if(timerBall > timeBallMax) + if(timerball > timeballmax) { - timerBall = 0.0f; - if(!projectiles[countSphere % SPHERE_NB].activeInHierarchy) + timerball = 0.0f; + if(!projectiles[countsphere % SPHERE_NB].activeInHierarchy) { - projectiles[countSphere % SPHERE_NB].SetActive(true); + projectiles[countsphere % SPHERE_NB].SetActive(true); } - projectiles[countSphere % SPHERE_NB].transform.rotation = launcher.transform.rotation; - projectiles[countSphere % SPHERE_NB].transform.position = launcher.transform.position; + projectiles[countsphere % SPHERE_NB].transform.rotation = launcher.transform.rotation; + projectiles[countsphere % SPHERE_NB].transform.position = launcher.transform.position; float offsetAngleX = 0.0f; float offsetAngleY = 0.0f; launcher.transform.localRotation = Quaternion.Euler(-offsetAngleY * Mathf.Rad2Deg, -offsetAngleX * Mathf.Rad2Deg, 0); - projectiles[countSphere % SPHERE_NB].GetComponent().ResetValues(); - Rigidbody rigidBody = projectiles[countSphere % SPHERE_NB].GetComponent(); + projectiles[countsphere % SPHERE_NB].GetComponent().ResetValues(); + Rigidbody rigidBody = projectiles[countsphere % SPHERE_NB].GetComponent(); rigidBody.velocity = Vector3.zero; rigidBody.isKinematic = false; rigidBody.useGravity = true; rigidBody.AddForce(launcher.transform.forward * LaunchIntensity); - times[countSphere % SPHERE_NB] = 0; - countSphere++; + times[countsphere % SPHERE_NB] = 0; + countsphere++; } - timerBall += Time.deltaTime; + timerball += Time.deltaTime; } for (int i = 0; i < SPHERE_NB; i++) { diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallTrigger.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallTrigger.cs index 80d84856..f8231170 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallTrigger.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/BallTrigger.cs @@ -3,7 +3,8 @@ using UnityEngine; /// -/// Send events when the ball has touched an object +/// Previously used in the ZED spatial mapping sample scene. +/// Sends events when the ball the script is attached to has touched an object. /// public class BallTrigger : MonoBehaviour { diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyBehavior.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyBehavior.cs index 74d619d6..e92562bf 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyBehavior.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyBehavior.cs @@ -3,7 +3,8 @@ using UnityEngine; /// -/// Spawns and destroys the bunnies +/// Previously used in the ZED spatial mapping sample scene. +/// Spawns and destroys the bunnies. /// public class EnemyBehavior : MonoBehaviour { diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyManager.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyManager.cs index bd6bea04..7451d86c 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyManager.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/EnemyManager.cs @@ -1,48 +1,53 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; + /// -/// Positions the enemies and controll their death +/// Spawns the specified prefab and positions it when a NavMeshSurface reports there's +/// a new NavMesh it can walk on. Used in the ZED spatial mapping sample scene to spawn a bunny +/// to walk around your environment once you're done scanning it. /// public class EnemyManager : MonoBehaviour { /// - /// List of all the enemies - /// - static List enemies = new List(); - - /// - /// The prefab used to spawn the enemy + /// The prefab used to spawn the enemy. Should contain a NavMeshAgent component. /// + [Tooltip("The prefab used to spawn the enemy. Should contain a NavMeshAgent component. ")] public GameObject enemyPrefab; /// - /// Check if the NavMesh is ready + /// Whether or not the NavMesh from the NavMeshSurface is ready. /// private bool isReady = false; /// - /// Number of tries to set a prefab + /// Number of tries the script has attempted to place the prefab on the NavMesh. It stops trying at 20. /// private int noNavMeshCount = 0; /// - /// Center of the current navMesh + /// Center of the current navMesh. /// private Vector3 centerNavMesh; /// - /// Type of agent accepted by the NavMesh + /// ID of agent type accepted by the NavMesh. Agent IDs are defined in the Navigation window. /// private int agentTypeNavMeshID = 0; /// - /// Type of the agent from the prefab + /// ID of the agent type from the prefab's NavMeshAgent component. Agent IDs are defined in the Navigation window. /// private int agentType = 0; + + /// + /// List of all instantiated enemies. + /// + static List enemies = new List(); + void Update() { - //Try to create an enemy on the navMesh + //Try to create an enemy on the NavMesh. if (isReady && enemies.Count == 0 && noNavMeshCount < 20) { Create(); @@ -55,7 +60,11 @@ void Update() } } - //A new navmesh has been created + /// + /// Called when ZEDSpatialMapping begins making a new mesh, to clear existing enemies + /// and prevent the script from trying to place enemies. + /// Subscribed to ZEDSpatialMapping.OnMeshStarted in OnEnable(). + /// void StartNavMesh() { //Clear all the enemies @@ -90,12 +99,15 @@ private void Start() private void OnDisable() { + //Unsubscribe from the events. ZEDSpatialMapping.OnMeshStarted -= StartNavMesh; NavMeshSurface.OnNavMeshReady -= Ready; } /// - /// Event sent from the NavMesh + /// Called when the NavMesh is finished being created, to clear existing data + /// and begin trying to place the enemy. + /// Subscribed to NavMeshSurface.OnNavMeshReady in OnEnable(). /// /// /// @@ -135,21 +147,21 @@ static void Destroyed(GameObject o) } /// - /// Try to create an agent on the navMesh + /// Try to create an agent on the NavMesh. /// public void Create() { - //If the agent and the navMesh have two area type different + //If the agent and the NavMesh have different agent IDs, don't assign it. if (agentType != agentTypeNavMeshID) { Debug.LogWarning("The agent ID differs from the NavMesh"); return; } - //Create a gameobject to try to set it on the NavMesh + //Instantiate the prefab and try to place it on the NavMesh. enemies.Add(Instantiate(enemyPrefab, centerNavMesh, Quaternion.identity)); List notActivated = new List(); - //For each enemy created move it on the navMesh + //For each enemy created, move it on the NavMesh. foreach (GameObject o in enemies) { NavMeshAgentController a = o.GetComponent(); @@ -166,7 +178,7 @@ public void Create() } } - //Destroy the objects missing the NavMesh + //Destroy any objects that were not properly added to the NavMesh. foreach (GameObject o in notActivated) { Destroy(o); diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshAgentController.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshAgentController.cs index b5eae35a..220274f6 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshAgentController.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshAgentController.cs @@ -5,25 +5,27 @@ using UnityEngine.AI; /// -/// Sets the position of all the navMesh agents when they spawn +/// Used in the ZED spatial mapping sample scene to position new nav mesh agents randomly onto a +/// new NaVMesh when they're spawned. /// public class NavMeshAgentController : MonoBehaviour { - /// - /// Distance between current position and target + /// Maximum distance between the starting position where the agent can be randomly placed. /// + [Tooltip("Maximum distance between the starting position where the agent can be randomly placed.")] public float rangeAroundCurrentPosition = 5.0f; /// - /// Random position around an area. The position will always be on the ground + /// Finds a random position around a given point. The position will always be on the ground. /// - /// - /// - /// - /// + /// The point around where the random position appears. + /// The maximum distance from the center that the random position can be. + /// The random position. + /// True if it found a valid location. bool RandomPoint(Vector3 center, float range, out Vector3 result) { + //Try up to 30 times to find a valid point near center. Return true as soon as one is found. for (int i = 0; i < 30; i++) { Vector3 vector = Random.insideUnitSphere * range; @@ -51,9 +53,9 @@ bool RandomPoint(Vector3 center, float range, out Vector3 result) /// - /// Sets the target position of the agent + /// Sets the target position of the agent to a random point /// - /// + /// True if it successfully placed the agent. public bool Move() { Vector3 point; diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshSurface.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshSurface.cs index 18665e52..c326e442 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshSurface.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/NavMeshSurface.cs @@ -8,64 +8,104 @@ #endif /// -/// Creates and draws the NavMesh +/// Takes a mesh supplied by ZEDSpatialMappingManager after a scan and converts it into a +/// NavMesh at runtime that can be used for AI pathfinding. +/// If this script is present, the process will happen automatically when a scan is completed. +/// See the ZED spatial mapping tutorial for more info: https://docs.stereolabs.com/mixed-reality/unity/spatial-mapping-unity/ /// [RequireComponent(typeof(ZEDSpatialMappingManager))] public class NavMeshSurface: MonoBehaviour { +#if UNITY_5_6_OR_NEWER + /// + /// The ID of the agent type the NavMesh will be built for. + /// See available agent types (or create a new one) in Unity's Navigation window. + /// + [SerializeField] + public int agentTypeID = 0; -#if UNITY_5_6_OR_NEWER /// - /// List of sources built from meshes + /// List of all NavMeshBuildSource objects the script creates to make the final mesh. + /// One is created for each 'chunk' of the scan. /// private List sources = new List(); /// - /// Final nav mesh + /// The final NavMesh. /// private NavMeshData navMesh; /// - /// Bounds of the mesh, it is computed at the collect of mesh + /// Outside bounds of the mesh. Computed after all the chunks have been collected. /// private Bounds bounds; - [SerializeField] - public int agentTypeID = 0; + /// + /// Material used to display the final NavMesh in the editor. + /// Normally Mat_ZED_Transparent_NavMesh. + /// private Material materialTransparent; #endif - + /// + /// Arguments passed by NavMeshSurface's OnNavMeshReady event, so a class that places NPCs + /// (like EnemyManager) can place said NPC properly. + /// public class PositionEventArgs : System.EventArgs { + /// + /// The world space position of the center of the new NavMesh. + /// public Vector3 position; + + /// + /// Whether the NavMesh created is valid for placement (and drawing) purposes. + /// public bool valid = false; + + /// + /// The ID of the NavMesh's agent type. + /// public int agentTypeID = 0; } /// - /// Event when the navMesh is ready + /// Event that gets called when the NavMesh is finished being created. /// public static event System.EventHandler OnNavMeshReady; /// - /// Reference to the spatial mapping + /// Reference to this GameObject's ZEDSpatialMappingManager component. /// private ZEDSpatialMappingManager zedSpatialMapping; + /// + /// Whether to display the NavMesh in the editor. + /// [HideInInspector] [SerializeField] public bool hideFlag = false; + /// + /// Whether the NavMesh construction is finished or not. + /// [HideInInspector] [SerializeField] public bool isOver = false; /// - /// Navmesh object created + /// The GameObject that represents the NavMesh visually. /// private GameObject navMeshObject; + + /// + /// World space position of the final NavMesh. + /// private Vector3 navMeshPosition; + /// + /// Public accessor for the world space position of the final NavMesh. + /// public Vector3 NavMeshPosition { get { return navMeshObject != null ? navMeshPosition : Vector3.zero; } } + // Use this for initialization void Start() { @@ -75,39 +115,47 @@ void Start() navMesh = new NavMeshData(); NavMesh.AddNavMeshData(navMesh); - //Initialize a position of the bound + //Initialize a position for the bounds. bounds = new Bounds(transform.position, new Vector3(30, 30, 30)); - materialTransparent = Resources.Load("Materials/Mat_ZED_Transparent_NavMesh") as Material; + materialTransparent = Resources.Load("Materials/Mat_ZED_Transparent_NavMesh") as Material; //The material applied to the display object. #endif } void OnEnable() { + //Listen for when the spatial mapping starts scanning, and when it's finished. ZEDSpatialMapping.OnMeshReady += MeshIsOver; ZEDSpatialMapping.OnMeshStarted += NewNavMesh; } + /// + /// Clears the existing display object, if one exists. + /// void NewNavMesh() { if(navMeshObject != null) { - Destroy(navMeshObject); + Destroy(navMeshObject); } } void OnDisable() { + //Unsubscribe from events, as they can otherwise still fire when this component is disabled. ZEDSpatialMapping.OnMeshReady -= MeshIsOver; ZEDSpatialMapping.OnMeshStarted -= NewNavMesh; - } + /// + /// Called when a new NavMesh has finished being processed. + /// Updates several values and calls the OnMeshReady event with the proper arguments. + /// void MeshIsOver() { #if UNITY_5_6_OR_NEWER UpdateNavMesh(); - //Nav mesh has been build. Clear the sources as we don't need them + //Nav mesh has been built. Clear the sources as we don't need them sources.Clear(); //Draw the nav mesh is possible (triangulation from navmesh has return an area) @@ -135,9 +183,9 @@ void MeshIsOver() } /// - /// Draws the navMesh + /// Creates a mesh with the same shape as the NavMesh for the display object. /// - /// + /// Whether the mesh is valid. bool Draw() { NavMeshTriangulation triangulation = NavMesh.CalculateTriangulation(); @@ -145,7 +193,7 @@ bool Draw() if (triangulation.areas.Length == 0) return false; - + //Create a child object of this one that displays the NavMesh. if (navMeshObject == null) { navMeshObject = new GameObject("NavMesh"); @@ -170,12 +218,13 @@ bool Draw() } r.sharedMaterial = materialTransparent; navMeshPosition = r.bounds.center; - navMeshObject.SetActive(hideFlag); + navMeshObject.SetActive(hideFlag); //Hidden by default. return true; } /// - /// Collect all the submeshes to build the Nav Mesh + /// Collect all the submeshes, or 'chunks', converts them into NavMeshBuildSource objects, + /// then fills the sources list with them. /// void CollectSources() { @@ -199,45 +248,44 @@ void CollectSources() #endif } - - - /// - /// Calculates the bounds once sources have been collected and inflate them - /// - /// Sources. - void CalculateBounds(List sources) + /// + /// Calculates the NavMesh's bounds and inflates them slightly. + /// Called after all NavmeshBuildSource objects have been created. + /// + /// Sources. + void CalculateBounds(List sources) { - // Use the unscaled matrix for the NavMeshSurface + //Use the unscaled matrix for the NavMeshSurface. if (sources.Count != 0) { bounds.center = transform.position; - //For each src, grows the bounds + //For each source, grows the bounds. foreach (var src in sources) { Mesh m = src.sourceObject as Mesh; bounds.Encapsulate (m.bounds); } } - // Inflate the bounds a bit to avoid clipping co-planar sources + //Inflate the bounds a bit to avoid clipping co-planar sources. bounds.Expand(0.1f); } /// - /// Collect the meshes and construct a nav mesh + /// Collects the meshes and constructs a single NavMesh from them. /// void UpdateNavMesh() { isOver = false; - // First collect all the sources (submeshes) + //First collect all the sources (submeshes). CollectSources(); #if UNITY_5_6_OR_NEWER if (sources.Count != 0) { - // adjust bounds + //Adjust bounds. CalculateBounds(sources); - // update the nav mesh with sources and bounds + //Update the NavMesh with sources and bounds. var defaultBuildSettings = NavMesh.GetSettingsByID(agentTypeID); NavMeshBuilder.UpdateNavMeshData(navMesh, defaultBuildSettings, sources, bounds); } @@ -246,7 +294,7 @@ void UpdateNavMesh() #if UNITY_5_6_OR_NEWER /// - /// Hide or display the navmesh drawn + /// Hide or display the NavMesh using the display object (navMeshObject). /// public void SwitchStateDisplayNavMesh() { @@ -266,41 +314,58 @@ private void OnApplicationQuit() } #if UNITY_5_6_OR_NEWER #if UNITY_EDITOR - +/// +/// Custom editor for NavMeshSurface to extend how it's drawn in the Inspector. +/// It adds a custom drop-down for agent types, and the Display button that toggles the NavMesh's visibility. +/// [CustomEditor(typeof(NavMeshSurface))] class ZEDNavMeshEditor : Editor { - + //Represent the relevant properties as SerializedProperties. + //This lets us manipulate and also save (serialize) the data in the scene. + /// + /// Bound to agentTypeID, the agent type of the NavMesh. + /// SerializedProperty agentID; + /// + /// Bound to hideFlag, whether the NavMesh is visible or not. + /// SerializedProperty hideFlag; + /// + /// Bound to isOver, whether the NavMesh has been calculated or not. + /// SerializedProperty isOver; - ZEDNavMeshEditor() - { - - } private void OnEnable() { + //Bind the serialized properties to the relevant properties in NavMeshSurface. agentID = serializedObject.FindProperty("agentTypeID"); hideFlag = serializedObject.FindProperty("hideFlag"); isOver = serializedObject.FindProperty("isOver"); } + /// + /// Creates a custom drop-down for the Agent Type enum, which includes a button to + /// open the Navigation window for creating/looking up agent types. + /// + /// Text of the label beside the drop-down. Usually "Agent Type". + /// SerializedProperty that the drop-down reads/writes. public static void AgentTypePopup(string labelName, SerializedProperty agentTypeID) { var index = -1; var count = NavMesh.GetSettingsCount(); - var agentTypeNames = new string[count + 2]; + //var agentTypeNames = new string[count + 2]; + GUIContent[] agentTypeNames = new GUIContent[count + 2]; for (var i = 0; i < count; i++) { var id = NavMesh.GetSettingsByIndex(i).agentTypeID; var name = NavMesh.GetSettingsNameFromID(id); - agentTypeNames[i] = name; + agentTypeNames[i] = new GUIContent(name); if (id == agentTypeID.intValue) index = i; } - agentTypeNames[count] = ""; - agentTypeNames[count + 1] = "Open Agent Settings..."; + agentTypeNames[count] = new GUIContent(""); + agentTypeNames[count + 1] = new GUIContent("Open Agent Settings..."); bool validAgentType = index != -1; if (!validAgentType) @@ -312,7 +377,8 @@ public static void AgentTypePopup(string labelName, SerializedProperty agentType EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID); EditorGUI.BeginChangeCheck(); - index = EditorGUI.Popup(rect, labelName, index, agentTypeNames); + GUIContent text = new GUIContent(labelName, "The ID of the agent type the NavMesh will be built for."); + index = EditorGUI.Popup(rect, text, index, agentTypeNames); if (EditorGUI.EndChangeCheck()) { if (index >= 0 && index < count) @@ -335,12 +401,13 @@ public override void OnInspectorGUI() serializedObject.Update(); AgentTypePopup("Agent Type", agentID); - GUI.enabled = isOver.boolValue; - if (GUILayout.Button(hideFlag.boolValue ? "Hide" : "Display")) + GUI.enabled = isOver.boolValue; //Only let the user click the button if the NavMesh is finished. + GUIContent text = new GUIContent(hideFlag.boolValue ? "Hide" : "Display", "Toggle the visibility of the NavMesh."); + if (GUILayout.Button(text)) { - obj.SwitchStateDisplayNavMesh(); + obj.SwitchStateDisplayNavMesh(); //Switch the setting to whatever it wasn't before. } - serializedObject.ApplyModifiedProperties(); + serializedObject.ApplyModifiedProperties(); //Applies everything we just changed. } } #endif diff --git a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/RandomWalk.cs b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/RandomWalk.cs index c61fa70a..157c2e5d 100644 --- a/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/RandomWalk.cs +++ b/ZEDCamera/Assets/ZED/Examples/SpatialMapping/Scripts/RandomWalk.cs @@ -4,34 +4,44 @@ using UnityEngine.AI; /// -/// Sets the agent to randomly walk in a certain area +/// Tells the attached NavMeshAgent component to walk to a random location, and finds a new location +/// each time it arrives. +/// Used in the ZED spatial mapping sample to make the bunny character walk around once you've finished +/// scanning your environment. /// +[RequireComponent(typeof(NavMeshAgent))] public class RandomWalk : MonoBehaviour { /// - /// Range of search available + /// Maximum distance of the next random point to walk to. /// - public float m_Range = 25.0f; + [Tooltip("Maximum distance of the next random point to walk to.")] + public float maxRange = 25.0f; /// - /// Reference to the component agent + /// The NavMeshAgent component attached to this GameObject. /// private NavMeshAgent m_agent; /// - /// flag to set the agent to walk + /// Whether the agent should be walking. /// private bool startWalking = false; /// - /// Destination to walk to + /// Current random destination the agent is walking toward. /// private Vector3 destination; /// - /// Reduce the range of research if the future position is hard to find + /// Factor used to narrow the range of possible random destinations if positions at the range are difficult to find. /// private uint reduceFactor = 0; + + /// + /// Enables the agent component and begins walking. + /// Called by EnemyManager once the agent is successfully placed. + /// public void Activate() { m_agent = GetComponent(); @@ -39,8 +49,6 @@ public void Activate() startWalking = true; } - - void Update() { if (startWalking) @@ -52,9 +60,9 @@ void Update() reduceFactor = 0; return; } - destination = (Mathf.Abs(m_Range) - reduceFactor) * Random.insideUnitSphere; + destination = (Mathf.Abs(maxRange) - reduceFactor) * Random.insideUnitSphere; m_agent.destination = destination; - if(reduceFactor < Mathf.Abs(m_Range)/2) reduceFactor++; + if(reduceFactor < Mathf.Abs(maxRange)/2) reduceFactor++; } } } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs index fce95a1f..ec4341fb 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs @@ -3,67 +3,70 @@ using UnityEngine; /// -/// Displays the point cloud in front of the camera +/// Displays the point cloud of the real world in front of the camera. +/// Can be attached to any GameObject in a scene, but requires a ZEDManager component to exist somewhere. /// public class ZEDPointCloudManager : MonoBehaviour { /// - /// This camera will not see the point cloud + /// Set to a camera if you do not want that camera to see the point cloud. /// + [Tooltip("Set to a camera if you do not want that camera to see the point cloud. ")] public Camera hiddenObjectFromCamera; /// - /// Number of points displayed usually, the WIDTH*HEIGHT of the ZED + /// Number of points displayed. Usually equal to the width * height of the ZED's resolution (eg. 1280 * 720). /// private int numberPoints = 0; /// - /// Instance of the ZED + /// Instance of the ZEDCamera interface. /// private sl.ZEDCamera zed; /// - /// 3D position of the points + /// Texture that holds the 3D position of the points. /// private Texture2D XYZTexture; /// - /// Color of each point + /// Texture that holds the colors of each point. /// private Texture2D colorTexture; /// - /// Temporary copy of the XYZTexture to stop the point cloud to a defined moment + /// Temporary copy/buffer of the XYZTexture to stop the point cloud in a defined moment. /// private RenderTexture XYZTextureCopy = null; /// - /// Temporary copy of the ColorTexture to stop the point cloud to a defined moment + /// Temporary copy/buffer of the ColorTexture to stop the point cloud in a defined moment. /// private RenderTexture ColorTextureCopy = null; /// - /// Material used to display the point cloud + /// Material used to display the point cloud. Usually Mat_ZED_PointCloud. /// private Material mat; /// - /// It's the current state of display. If set to false the point cloud will be hidden + /// Whether the point cloud should be visible or not. /// + [Tooltip("Whether the point cloud should be visible or not. ")] public bool display = true; /// - /// It's the cuurent state of updating. - /// If set to false, the point cloud will not be updated and will be drawn with the content of the temp textures + /// Whether to update the point cloud. + /// If false, the point cloud will display the content of the temp textures from the last update. /// + [Tooltip("Whether to update the point cloud. If false, the point cloud will display the content of the temp textures from the last update. ")] public bool update = true; /// - /// Falg to check if the update has changed state + /// Flag to check if the update has changed state. /// private bool previousUpdate = true; - void Start() { zed = sl.ZEDCamera.GetInstance(); @@ -72,16 +75,17 @@ void Start() // Update is called once per frame void Update() { - if (zed.IsCameraReady) + if (zed.IsCameraReady) //Don't do anything unless the ZED has been initialized. { if (numberPoints == 0) { - //Creations of the textures + //Create the textures. These will be updated automatically by the ZED. + //We'll copy them each frame into XYZTextureCopy and ColorTextureCopy, which will be the ones actually displayed. XYZTexture = zed.CreateTextureMeasureType(sl.MEASURE.XYZ); colorTexture = zed.CreateTextureImageType(sl.VIEW.LEFT); numberPoints = zed.ImageWidth * zed.ImageHeight; - //Load and set the materials properties + //Load and set the material properties. mat = Resources.Load("Materials/PointCloud/Mat_ZED_PointCloud") as Material; if (mat != null) { @@ -105,8 +109,7 @@ void Update() ColorTextureCopy = new RenderTexture(colorTexture.width, colorTexture.height, 0, RenderTextureFormat.ARGB32); } - - + //Copy the new textures into the buffers. Graphics.Blit(XYZTexture, XYZTextureCopy); Graphics.Blit(colorTexture, ColorTextureCopy); @@ -116,7 +119,7 @@ void Update() mat.SetTexture("_ColorTex", ColorTextureCopy); } } - //Display the right textures + //Send the textures to the material/shader. if (update && previousUpdate != update && mat != null) { mat.SetTexture("_XYZTex", XYZTexture); @@ -131,6 +134,7 @@ void Update() void OnApplicationQuit() { + //Free up memory. mat = null; if (XYZTextureCopy != null) { @@ -149,7 +153,8 @@ void OnRenderObject() { if (hiddenObjectFromCamera == Camera.current) return; - if (!display) return; + if (!display) return; //Don't draw anything if the user doesn't want to. + mat.SetMatrix("_Position", transform.localToWorldMatrix); mat.SetPass(0); Graphics.DrawProcedural(MeshTopology.Points, 1, numberPoints); diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs index 26af3f46..d782e4ba 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs @@ -3,12 +3,13 @@ using UnityEngine; using UnityEngine.Rendering; /// -/// Helping functions for the post processing +/// Helper functions for the post processing effects applied to the final mixed reality image. +/// Used by ZEDRenderingPlane when Post-Processing is enabled, and always used by GreenScreenManager. /// public class ZEDPostProcessingTools { /// - /// Returns the gaussian value for f(x) = (1/2*3.14*s)*e(-x*x/(2*s)) + /// Returns the gaussian value for f(x) = (1/2*3.14*s)*e(-x*x/(2*s)). /// /// /// @@ -19,7 +20,7 @@ public static float Gaussian(float x, float sigma) } /// - /// Compute weights to be sent to the blur shader + /// Computes weights to be sent to the blur shader. /// /// /// @@ -48,7 +49,7 @@ public static void ComputeWeights(float sigma, out float[] weights_, out float[] weights[i] /= sum; } - // fix for just 3 fetches + //Fix for just 3 fetches weights_[0] = weights[0]; weights_[1] = weights[1] + weights[2]; weights_[2] = weights[3] + weights[4]; @@ -62,12 +63,12 @@ public static void ComputeWeights(float sigma, out float[] weights_, out float[] /// /// Blurs a render texture. /// - /// - /// - /// Material used to blur - /// The pass used by the material - /// More iterations means a more prominent blur - /// The downscale of the source, more blur, and less computation time + /// Source RenderTexture. + /// RenderTexture that the blurred version will be rendered into. + /// Material used to blur. + /// The pass used by the material. + /// More iterations means a more prominent blur. + /// The downscale of the source, which increases blur and decreases computation time. public static void Blur(RenderTexture source, RenderTexture dest, Material mat, int pass, int numberIterations = -1, int downscale = 2) { @@ -88,12 +89,12 @@ public static void Blur(RenderTexture source, RenderTexture dest, Material mat, { bool oddEven = false; - //Create two buffers to make a multi-pass blur + //Create two buffers to make a multi-pass blur. RenderTexture buffer2 = RenderTexture.GetTemporary(source.width / downscale, source.height / downscale, source.depth, source.format, RenderTextureReadWrite.Default); Graphics.Blit(source, buffer); - //To each pass alternate the buffer, and set the blur direction + //To each pass, alternate the buffer, and set the blur direction. for (int i = 0; i < numberIterations * 2; i++) { mat.SetInt("horizontal", System.Convert.ToInt32(oddEven)); @@ -106,7 +107,7 @@ public static void Blur(RenderTexture source, RenderTexture dest, Material mat, { mat.SetInt("horizontal", System.Convert.ToInt32(oddEven)); - //Copy the buffer to the final texture + //Copy the buffer to the final texture. if (oddEven) { Graphics.Blit(buffer2, dest, mat, pass); @@ -117,12 +118,16 @@ public static void Blur(RenderTexture source, RenderTexture dest, Material mat, } } } - //Destroy all the temporary buffers + //Destroy all the temporary buffers. RenderTexture.ReleaseTemporary(buffer2); } RenderTexture.ReleaseTemporary(buffer); } + /// + /// Holds IDs of shader properties. Used because setting a property by ID is faster than + /// setting it by a property name. + /// static class Uniforms { internal static readonly int _MainTex = Shader.PropertyToID("_MainTex"); @@ -135,12 +140,12 @@ static class Uniforms /// /// Blurs a render texture. /// - /// - /// + /// CommandBuffer from where the rendertexture is taken. + /// RenderTexture to be blurred. /// Material used to blur /// The pass used by the material /// More iterations means a more prominent blur - /// The downscale of the source, more blur, and less computation time + /// The downscale of the source, which increases blur and decreases computation time. public static void Blur(CommandBuffer cb, RenderTexture texture, Material mat, int pass, int numberIterations = -1, int downscale = 2) { @@ -159,7 +164,6 @@ public static void Blur(CommandBuffer cb, RenderTexture texture, Material mat, i bool oddEven = false; //Create two buffers to make a multi-pass blur - cb.Blit(texture, Uniforms._TempRT); //To each pass alternate the buffer, and set the blur direction for (int i = 0; i < numberIterations * 2; i++) @@ -186,10 +190,8 @@ public static void Blur(CommandBuffer cb, RenderTexture texture, Material mat, i } } //Destroy all the temporary buffers - // RenderTexture.ReleaseTemporary(buffer2); cb.ReleaseTemporaryRT(Uniforms._TempRT); cb.ReleaseTemporaryRT(Uniforms._TempRT2); - // RenderTexture.ReleaseTemporary(buffer); } public static void ComposeMask(CommandBuffer cb, RenderTexture mask, Material matStencilToMask, Material matComposeMask) @@ -198,14 +200,15 @@ public static void ComposeMask(CommandBuffer cb, RenderTexture mask, Material ma cb.GetTemporaryRT(Uniforms._TempRT2, -1, -1, 24); cb.Blit(mask, Uniforms._TempRT); - // this is fine, set up the target and clear + //This is fine, set up the target and clear. cb.SetRenderTarget(Uniforms._TempRT2); cb.ClearRenderTarget(false, true, Color.black); - //To keep the stencil in post process + + //To keep the stencil in post process. cb.SetRenderTarget(Uniforms._TempRT2, BuiltinRenderTextureType.CurrentActive); cb.Blit(BuiltinRenderTextureType.CameraTarget, Uniforms._TempRT2, matStencilToMask); - //cb.DrawMesh(UnityEngine.PostProcessing.GraphicsUtils.quad, Matrix4x4.identity, matStencilToMask); - //Compose the second mask get in the forward pass. The shader should set the stencil to 148 + + //Compose the second mask retrieved in the forward pass. The shader should set the stencil to 148. //cb.Blit(mask, Uniforms._TempRT); cb.SetGlobalTexture("_Mask", Uniforms._TempRT); // matComposeMask.set("_Mask", Uniforms._TempRT); diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs index 7678b2f1..91ac2518 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs @@ -5,16 +5,18 @@ /// -/// Displays the image of the ZED into a quad. -/// Inserts the depth and normals inside the pipeline -/// Compute the data for the light and send them to the shaders -/// Post-processes the image +/// Responsible for actually mixing the real and virtual images, and displaying them in a +/// Frame object within the camera rig. +/// First, it displays the image of the ZED into a quad. +/// Then, it inserts the depth and normals inside the pipeline +/// Third, it computes the data for the light and send it to the shaders. +/// Finally, it post-processes the image, if post-processing is enabled. /// [RequireComponent(typeof(Camera))] public class ZEDRenderingPlane : MonoBehaviour { /// - /// The rendering mode accepted + /// The rendering mode accepted. /// enum ZED_RENDERING_MODE { @@ -25,115 +27,132 @@ enum ZED_RENDERING_MODE /// - /// The screen is the quad where the textures are displayed + /// The GameGbject that displays the final textures. + /// In the ZED_Rig_Mono and ZED_Rig_Stereo prefabs, this is the Frame object that's a child of each camera. /// + [Tooltip("The GameGbject that displays the final textures. " + + "In the ZED_Rig_Mono and ZED_Rig_Stereo prefabs, this is the Frame object that's a child of each camera.")] public GameObject canvas; /// - /// It's the main material, used to set the color and the depth + /// The main material, set to the one on the canvas's MeshRenderer. Used to set the color and depth. /// private Material matRGB; /// - /// All the textures displayed are in 16/9 + /// Aspect ratio of the textures. All the textures displayed should be in 16:9. /// private float aspect = 16.0f / 9.0f; /// - /// The main camera is the virtual camera controlled by the ZED + /// The Camera component representing an 'eye' of the ZED. Must be on the same GameObject as this component. /// - private Camera mainCamera; + private Camera cam; /// - /// The link to the ZED SDK + /// Reference to the ZED SDK. /// private sl.ZEDCamera zedCamera; /// - /// Texture generated from the ZED, it may be the from the left or right eye of the ZED + /// Texture of the real world generated from the ZED. It may be the from the left or right 'eye.' + /// Once created, the ZED SDK automatically updates it with each frame/image the ZED captures. /// private Texture2D textureEye; public Texture2D TextureEye { get { return textureEye; } } /// - /// Depth generated by the ZEDCamera + /// Depth generated by the ZEDCamera. + /// Once created, the ZED SDK automatically updates it whenever the ZED captures new frames/images. /// Texture2D depth; /// - /// Normals generated by the ZEDCamera + /// Normals generated by the ZEDCamera. + /// Once created, the ZED SDK automatically updates it whenever the ZED captures new frames/images. /// Texture2D normals; /// - /// CommandBuffer to integrate the depth in the pipeline of Unity for deferred and forward + /// CommandBuffer to integrate the depth into Unity's forward or deferred pipeline. /// CommandBuffer[] buffer = new CommandBuffer[(int)ZED_RENDERING_MODE.LAST]; /// - /// CommandBuffer to create a mask for the virtual objects in forward and deferred + /// CommandBuffer to create a mask for the virtual objects in forward and deferred rendering. /// CommandBuffer[] postProcessBuffer = new CommandBuffer[(int)ZED_RENDERING_MODE.LAST]; /// - /// The material used to integrate the depth in forward mode after the depth texture is created, mainly use to get the shadows. Not needed for the light only + /// The material used to integrate the depth in forward mode after the depth texture is created. Mainly used to get the shadows. Not needed for lighting otherwise. /// private Material forwardMat; /// - /// The material used to integrate the depth in deferred mode. Always used in deferred + /// The material used to integrate the depth in deferred mode. Always used in deferred regardless of lighting/shadows. /// private Material deferredMat; /// - /// The actual rendering path used + /// The actual rendering path used. + /// To change this, change the settings in Project Settings -> Graphics within the Unity editor. /// private RenderingPath actualRenderingPath = RenderingPath.VertexLit; public RenderingPath ActualRenderingPath { get { return actualRenderingPath; } } + + /// + /// The MeshFilter component of the canvas object. Used to draw the depth buffer. + /// MeshFilter meshCanvas; /// - /// A Low resolution of the textures from the ZED + /// A lower resolution of the depth and normals textures from the ZED. /// private sl.Resolution resolution = new sl.Resolution(384, 192); + /***LIGHTS definitions***/ /// - /// Point light structure sends to the shader via a compute buffer + /// Point light structure for virtual lights on the real world. + /// Gets sent to the shader via a compute buffer. /// [SerializeField] public struct PointLight { /// - /// the color * the intensity + /// The color, times the intensity. /// public Vector4 color; /// - /// the range of the light + /// The range of the light. /// public float range; /// - /// the position + /// The position of the light. /// public Vector3 position; } /// - /// Number of point light accepetd + /// Maximum number of point lights accepted. /// const int NUMBER_POINT_LIGHT_MAX = 8; /// - /// Point light container + /// Holds a slot for all point lights that should be cast on the real world. /// [SerializeField] public PointLight[] pointLights = new PointLight[NUMBER_POINT_LIGHT_MAX]; /// - /// Byte size to send to the shader + /// The size, or 'stride', of each PointLight in bytes. Needed to construct computeBufferPointLight. /// const int SIZE_POINT_LIGHT_BYTES = 32; - ComputeBuffer computeBuffePointLight; + + /// + /// Used to pass the pointLights array into matRGB's shader as a buffer. + /// + ComputeBuffer computeBufferPointLight; /// /// Structure of the spotlight send to the shader @@ -142,95 +161,132 @@ public struct PointLight public struct SpotLight { /// - /// The color * the intensity + /// The color, times the intensity. /// public Vector4 color; /// - /// The position + /// The position of the light. /// public Vector3 position; /// - /// The normalized direction and the angle + /// The light's normalized direction and angle. /// public Vector4 direction; /// - /// The parameters for the falloff + /// The parameters for the light's falloff. /// public Vector4 parameters; } /// - /// Number of spotlights accepted + /// Maximum number of spotlights accepted. /// const int NUMBER_SPOT_LIGHT_MAX = 8; + + /// + /// Holds a slot for all spotlights that should be cast on the real world. + /// [SerializeField] public SpotLight[] spotLights = new SpotLight[NUMBER_SPOT_LIGHT_MAX]; + + /// + /// The size, or 'stride', of each SpotLight in bytes. Needed to construct computeBufferSpotLight. + /// const int SIZE_SPOT_LIGHT_BYTES = 60; + /// - /// Number of light max rendered + /// Maximum number of total lights rendered (point and spot combined). /// const int NUMBER_LIGHTS_MAX = NUMBER_POINT_LIGHT_MAX / 2 + NUMBER_SPOT_LIGHT_MAX / 2; + /// - /// Data from a directional light, direction and color + /// Data from a directional light. [0] is its direction and [1] is its color. + /// Only one directional light is allowed at once. /// - private Vector4[] directionalLightData = new Vector4[2]; //Limit to one directional light + private Vector4[] directionalLightData = new Vector4[2]; + /// + /// Used to pass the spotLights array into matRGB's shader as a buffer. + /// ComputeBuffer computeBufferSpotLight; - //Forward ID shader cache + + //Forward ID shader caches. + /// + /// Property ID of the number of point lights in the ZED_Lighting shader include file. + /// private int numberPointLightsID; + + /// + /// Property ID of the number of spotlights in the ZED_Lighting shader include file. + /// private int numberSpotLightsID; - /*** Post process definitions***/ + /*** Post-process definitions***/ /// - /// The mask filled at runtime + /// The mask used for post-processing. Filled at runtime and updated each frame. /// private RenderTexture mask; /// - /// The post process material, to add noise and change the color + /// The post process material, used to add noise and change the color. /// private Material postprocessMaterial; + /// - /// Activate/Desactivate postprocess, the mask will not be generated anymore + /// Activate/deactivate post-processing. If false, the mask will not be generated. + /// Set by ZEDManager.setRenderingSettings() based on a checkbox in ZEDManager's custom editor. /// private bool ARpostProcessing = true; /// - /// The blurMaterial used to blur the mask + /// Used to blur the mask. /// private Material blurMaterial; + /// - /// A custom blit + /// Used to load a source image's alpha channel into all channels of a destination image. + /// Used during post-processing. /// private Material blitMaterial; + /// - /// A material to convert the stencil into a texture + /// Used to convert the stencil buffer of a rendertexture into a regular texture. /// private Material matStencilToMask; /// - /// Compose the mask from different textures + /// Used to compose the virtual mask from different textures. /// private Material matComposeMask; /// - /// Blend the textures from the ZEDMeshRenderer + /// Used to blend the textures from ZEDMeshRenderer, when present. + /// This adds the wireframe effect seen from 3D scanning or plane detection. /// private Material blender; - /// - /// View mode - /// - public sl.VIEW_MODE viewMode = sl.VIEW_MODE.VIEW_IMAGE; + /// + /// What kind of image the final result will display. Usually set to View. + /// Set this to VIEW_DEPTH or VIEW_NORMAL to see the live depth or normal maps. + /// + public sl.VIEW_MODE viewMode = sl.VIEW_MODE.VIEW_IMAGE; /// - /// Side of Rendering (Left == 0 or Right ==1) + /// Which side of the camera we render. Left = 0, Right ==1. /// private int side = 0; + /// + /// Default near plane value. Overrides camera's settings on start but will update if camera values change at runtime. + /// + private float nearplane = 0.1f; + /// + /// Default far plane value. Overrides camera's settings on start but will update if camera values change at runtime. + /// + private float farplane = 500.0f; /// - /// If AR, render the camera into a rendertarget + /// The target RenderTexture we'll render to if in AR mode. /// [HideInInspector] private RenderTexture renderTextureTarget; @@ -241,20 +297,31 @@ public RenderTexture target void Awake() { - //Get the current camera and set the aspect - mainCamera = GetComponent(); - mainCamera.aspect = aspect; - mainCamera.renderingPath = RenderingPath.UsePlayerSettings; - + //Get the current camera and set the aspect ratio. + cam = GetComponent(); + cam.aspect = aspect; + cam.renderingPath = RenderingPath.UsePlayerSettings; //Assigns the camera's rendering path to be consistent with the project's settings. } + /// + /// Whether or not post-processing effects are applied. + /// Usually set by ZEDManager based on the selection in its Inspector. + /// + /// public void SetPostProcess(bool c) { ARpostProcessing = c; } + /// + /// The object that forces the ZED image to be shown at 16:9 aspect ratio, regardless of the target window's resolution. + /// private WindowAspectRatio aspectRatio; + /// + /// Changes the scene's global lighting settings to prevent global illumnation from causing + /// lighting that doesn't match the real world. + /// private void SetUpGI() { RenderSettings.skybox = null; @@ -264,21 +331,24 @@ private void SetUpGI() DynamicGI.UpdateEnvironment(); } + /// + /// Configures materials/values/settings needed for post-processing and displaying in proper aspect ratio. + /// private void Start() { - //No environmental lighting per default + //No environmental lighting per default Shader.SetGlobalFloat("_ZEDExposure", -1); - //Load the materials + //Load the materials. matStencilToMask = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Stencil2Mask") as Material); matComposeMask = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_MaskCompositor") as Material); - //Load and configure the post process + //Load and configure the post-process material. postprocessMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_PostProcessing") as Material); postprocessMaterial.SetFloat("_gamma", 1.0f / (0.87f * 0.9f)); postprocessMaterial.SetFloat("_MinBlack", 15.0f / 255.0f); postprocessMaterial.SetInt("_NoiseSize", 2); - //Configure the weights for the blur + //Configure the weights for the blur effect. float[] weights; float[] offsets; ZEDPostProcessingTools.ComputeWeights(0.3f, out weights, out offsets); @@ -290,7 +360,7 @@ private void Start() blurMaterial.SetTexture("_Mask", mask); - //Force unity the 16:9 mode + //Force Unity into 16:9 mode to match the ZED's output. #if UNITY_EDITOR UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect16by9, true); UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect16by10, false); @@ -302,27 +372,30 @@ private void Start() //Load the blender for the zedmesher blender = new Material(Resources.Load("Materials/SpatialMapping/Mat_ZED_PostProcess_Blend") as Material); - //Set the bounds larger + //Set the bounds around the camera, used to detect if a point/spotlight is close enough to be applied. bounds = new Bounds(transform.position, new Vector3(20, 20, 20)); - // If AR REMOVE - aspectRatio = new WindowAspectRatio(mainCamera); + //IF AR REMOVE + aspectRatio = new WindowAspectRatio(cam); } - + /// + /// Configures numerous settings that can't be set until the ZED is fully initialized. + /// Subscribed to ZEDManager.OnZEDReady in OnEnable(). + /// void ZEDReady() { - //Add the fader + //Add the fade-in effect for when the camera first becomes visible. gameObject.AddComponent(); zedCamera = sl.ZEDCamera.GetInstance(); SetTextures(zedCamera,viewMode); canvas.SetActive(true); - canvas.transform.SetParent (mainCamera.transform); - ConfigureLightAndShadow(mainCamera.actualRenderingPath); + canvas.transform.SetParent (cam.transform); + ConfigureLightAndShadow(cam.actualRenderingPath); - //Move the plane with the optical centers + //Move the plane with the optical centers. float plane_distance =0.15f; Vector4 opticalCenters = zedCamera.ComputeOpticalCenterOffsets(plane_distance); @@ -332,27 +405,35 @@ void ZEDReady() canvas.transform.localPosition = new Vector3(opticalCenters.z, -1.0f * opticalCenters.w,plane_distance); - //Set the camera parameters and scale the screen + //Set the camera's parameters based on the ZED's, and scale the screen based on its distance. if (zedCamera.IsCameraReady) { - mainCamera.fieldOfView = zedCamera.VerticalFieldOfView * Mathf.Rad2Deg; - mainCamera.projectionMatrix = zedCamera.Projection; - mainCamera.nearClipPlane = 0.1f; - mainCamera.farClipPlane = 500.0f; - scale(canvas.gameObject, GetFOVYFromProjectionMatrix(mainCamera.projectionMatrix)); + cam.fieldOfView = zedCamera.VerticalFieldOfView * Mathf.Rad2Deg; + //mainCamera.projectionMatrix = zedCamera.Projection; + SetProjection(nearplane, farplane); + cam.nearClipPlane = nearplane; + cam.farClipPlane = farplane; + //mainCamera.nearClipPlane = 0.1f; + //mainCamera.farClipPlane = 500.0f; + scale(canvas.gameObject, GetFOVYFromProjectionMatrix(cam.projectionMatrix)); } - else + else //Just scale the screen. { - scale(canvas.gameObject, mainCamera.fieldOfView); + scale(canvas.gameObject, cam.fieldOfView); } } + /// + /// Hides the canvas. Called when the ZED is disconnected via the ZEDManager.OnZEDDisconnected event. + /// void ZEDDisconnected() { canvas.SetActive(false); } - + /// + /// Fixes GI, enables the canvas and subscribes to events from the ZED. + /// private void OnEnable() { SetUpGI(); @@ -363,6 +444,9 @@ private void OnEnable() ZEDManager.OnZEDDisconnected += ZEDDisconnected; } + /// + /// Disables the canvas and unsubscribes from events from the ZED. + /// private void OnDisable() { ZEDManager.OnZEDReady -= ZEDReady; @@ -370,13 +454,14 @@ private void OnDisable() canvas.SetActive(false); } - - //Invisible object to force unity to render shadow map + /// + /// Invisible object used to force Unity to render a shadow map. + /// GameObject forceShadowObject = null; /// - /// Configure the canvas to get and light and shadow + /// Configure the canvas to get and light and shadow. /// /// The current rendering path used private void ConfigureLightAndShadow(RenderingPath renderingPath) @@ -394,15 +479,16 @@ private void ConfigureLightAndShadow(RenderingPath renderingPath) { SetDeferred(); } - else + else //We're using an unknown rendering path. Log an error. { actualRenderingPath = current; - Debug.LogError(" [ ZED Plugin ] : The rendering path " + mainCamera.actualRenderingPath.ToString() + " is not compatible with the ZED"); + Debug.LogError(" [ ZED Plugin ] : The rendering path " + cam.actualRenderingPath.ToString() + " is not compatible with the ZED"); } } /// - /// Clear the depth buffer used + /// Clear the depth buffer used. + /// Called when configuring this script for the given rendering path (forward or deferred). /// private void ClearDepthBuffers() { @@ -421,52 +507,51 @@ private void ClearDepthBuffers() } /// - /// Configure the materials and buffer in forward mode + /// Configure the materials and buffer for the forward rendering path. /// private void SetForward() { ghasShadows = false; - blitMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Blit") as Material); Shader.SetGlobalInt("_HasShadows", 0); gameObject.transform.GetChild(0).GetComponent().enabled = true; - //Set textures to the shader + //Set the canvas's material to the material for forward rendering. matRGB = canvas.GetComponent().material; matRGB.SetInt("_isLinear", System.Convert.ToInt32(QualitySettings.activeColorSpace)); forwardMat = new Material(Resources.Load("Materials/Lighting/Mat_ZED_Forward") as Material); - // Configure the invisible object + // Configure the invisible object that forces Unity to calculate shadows. if (forceShadowObject == null) { ConfigureForceShadowObject(); } - //Set the textures into the materials + //Set the textures in the materials to the proper ones. matRGB.SetTexture("_MainTex", textureEye); matRGB.SetTexture("_CameraTex", textureEye); matRGB.SetTexture("_DepthXYZTex", depth); matRGB.SetTexture("_NormalsTex", normals); - forwardMat.SetTexture("_MainTex", textureEye); forwardMat.SetTexture("_DepthXYZTex", depth); - //Clear the buffers + //Clear the buffers. if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null) - mainCamera.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) - mainCamera.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + ClearDepthBuffers(); if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) - mainCamera.RemoveCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]); + cam.RemoveCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]); if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) { @@ -474,7 +559,7 @@ private void SetForward() postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] = null; } - //Set the depth buffer + //Set the depth buffer. buffer[(int)ZED_RENDERING_MODE.FORWARD] = new CommandBuffer(); buffer[(int)ZED_RENDERING_MODE.FORWARD].name = "ZED_DEPTH"; buffer[(int)ZED_RENDERING_MODE.FORWARD].SetRenderTarget(BuiltinRenderTextureType.CurrentActive); @@ -485,7 +570,7 @@ private void SetForward() mask = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.R8); } - //Set the post process + //Set up the post-processing material. postprocessMaterial.SetTexture("ZEDMaskPostProcess", mask); postprocessMaterial.SetTexture("ZEDTex", textureEye); @@ -494,16 +579,16 @@ private void SetForward() postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].Blit(BuiltinRenderTextureType.CameraTarget, mask, blitMaterial, 0); postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].SetGlobalTexture("_ZEDMaskVirtual", mask); - mainCamera.RemoveCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]); - mainCamera.AddCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.RemoveCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.AddCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]); - //Configure the light containers - if (computeBuffePointLight == null) + //Configure the light containers. + if (computeBufferPointLight == null) { - computeBuffePointLight = new ComputeBuffer(NUMBER_POINT_LIGHT_MAX, SIZE_POINT_LIGHT_BYTES); - computeBuffePointLight.SetData(pointLights); + computeBufferPointLight = new ComputeBuffer(NUMBER_POINT_LIGHT_MAX, SIZE_POINT_LIGHT_BYTES); + computeBufferPointLight.SetData(pointLights); - matRGB.SetBuffer("pointLights", computeBuffePointLight); + matRGB.SetBuffer("pointLights", computeBufferPointLight); } if (computeBufferSpotLight == null) @@ -513,47 +598,46 @@ private void SetForward() matRGB.SetBuffer("spotLights", computeBufferSpotLight); } - //Register the properties ID to improve the speed + //Register the property IDs to improve performance. (Setting properties by string is slower) numberPointLightsID = Shader.PropertyToID("numberPointLights"); numberSpotLightsID = Shader.PropertyToID("numberSpotLights"); } /// - /// Configure the materials and buffer for the deferred mode + /// Configure the materials and buffer for the deferred rendering path. /// private void SetDeferred() { - //Disable MSSA not supported with deferred + //Disable MSSA as it's not supported with deferred. #if UNITY_5_6_OR_NEWER - mainCamera.allowMSAA = false; + cam.allowMSAA = false; #endif - ghasShadows = false; deferredMat = new Material(Resources.Load("Materials/Lighting/Mat_ZED_Deferred") as Material); blitMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Blit") as Material); - //Sets the custom shader for the deferred pipeline + //Sets the custom shader for the deferred pipeline. GraphicsSettings.SetCustomShader(BuiltinShaderType.DeferredShading, (Resources.Load("Materials/Lighting/Mat_ZED_Deferred_Lighting") as Material).shader); deferredMat.SetMatrix("_Model", canvas.transform.localToWorldMatrix.transpose); - deferredMat.SetMatrix("_Projection", mainCamera.projectionMatrix); + deferredMat.SetMatrix("_Projection", cam.projectionMatrix); deferredMat.SetTexture("_MainTex", textureEye); deferredMat.SetTexture("_DepthXYZTex", depth); deferredMat.SetTexture("_NormalsTex", normals); - //clear the buffers + //Clear the buffers. if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null) - mainCamera.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) - mainCamera.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); if (postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] != null) - mainCamera.RemoveCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.RemoveCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]); if (postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] != null) { postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].Dispose(); @@ -562,11 +646,11 @@ private void SetDeferred() ClearDepthBuffers(); - //Set the depths buffer, the buffer will be changed if the camera allow HDR + //Set the depths buffer. This buffer will be changed if the camera is set to allow HDR. buffer[(int)ZED_RENDERING_MODE.DEFERRED] = new CommandBuffer(); buffer[(int)ZED_RENDERING_MODE.DEFERRED].name = "ZED_DEPTH"; - if (mainCamera.allowHDR) + if (cam.allowHDR) { RenderTargetIdentifier[] mrt = { BuiltinRenderTextureType.GBuffer0, BuiltinRenderTextureType.GBuffer1, BuiltinRenderTextureType.GBuffer2, BuiltinRenderTextureType.CameraTarget }; buffer[(int)ZED_RENDERING_MODE.DEFERRED].SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget); @@ -592,8 +676,8 @@ private void SetDeferred() - mainCamera.AddCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); - mainCamera.AddCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]); + cam.AddCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + cam.AddCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]); //Congigure the invisible object if (forceShadowObject == null) @@ -604,56 +688,68 @@ private void SetDeferred() } + /// + /// Sets up the invisible shadow GameObject that forces Unity to draw shadows. + /// private void ConfigureForceShadowObject() { forceShadowObject = GameObject.CreatePrimitive(PrimitiveType.Quad); forceShadowObject.name = "ZED_FORCE_SHADOW"; forceShadowObject.transform.parent = transform; - forceShadowObject.transform.localPosition = new Vector3(0, 0, mainCamera.nearClipPlane); + forceShadowObject.transform.localPosition = new Vector3(0, 0, cam.nearClipPlane); forceShadowObject.GetComponent().sharedMaterial = Resources.Load("Materials/Lighting/Mat_ZED_Hide") as Material; Destroy(forceShadowObject.GetComponent()); forceShadowObject.hideFlags = HideFlags.HideAndDontSave; } - //Bounds around the camera, it filters which camera are taken in forward mode + /// + /// The bounds around the camera that filter out point/spotlights that are too far away to be rendered. + /// private Bounds bounds; + + /// + /// Sets the camera's local pos/rot to origin/identity and sets up the RenderTexture if in stereo mode. + /// This RenderTexture is then displayed in hidden planes handled by ZEDMixedRealityPlugin where the final + /// output to the HMD is rendered. + /// private void CreateRenderTexture() { transform.localRotation = Quaternion.identity; transform.localPosition = new Vector3(0, 0, 0); - if (mainCamera.stereoTargetEye != StereoTargetEyeMask.None) + if (cam.stereoTargetEye != StereoTargetEyeMask.None) { if (zedCamera != null && zedCamera.IsCameraReady) { renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32); - mainCamera.targetTexture = renderTextureTarget; + cam.targetTexture = renderTextureTarget; } else if(sl.ZEDCamera.CheckPlugin()) { renderTextureTarget = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32); - mainCamera.targetTexture = renderTextureTarget; + cam.targetTexture = renderTextureTarget; } } } /// - /// Create and set the textures + /// Creates and sets the textures from the ZED, including image, depth and normals as needed. + /// Once created, the ZED SDK updates the textures automatically when the ZED sends new frames, so they don't need to be updated here. /// /// - private void SetTextures(sl.ZEDCamera zedCamera,sl.VIEW_MODE view_mode) + private void SetTextures(sl.ZEDCamera zedCamera, sl.VIEW_MODE view_mode) { float baseline = zedCamera.Baseline; canvas.transform.localRotation = Quaternion.identity; canvas.transform.localPosition = new Vector3(0, 0, 0); - if (StereoTargetEyeMask.Left == mainCamera.stereoTargetEye) + if (StereoTargetEyeMask.Left == cam.stereoTargetEye) //This camera is for the left HMD eye. { side = 0; if (zedCamera != null && zedCamera.IsCameraReady) { renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32); - mainCamera.targetTexture = renderTextureTarget; + cam.targetTexture = renderTextureTarget; } switch (view_mode) { @@ -672,13 +768,13 @@ private void SetTextures(sl.ZEDCamera zedCamera,sl.VIEW_MODE view_mode) depth = zedCamera.CreateTextureMeasureType(sl.MEASURE.DEPTH, resolution); } - else if (StereoTargetEyeMask.Right == mainCamera.stereoTargetEye) + else if (StereoTargetEyeMask.Right == cam.stereoTargetEye) //This camera is for the right HMD eye. { side = 1; if (zedCamera != null && zedCamera.IsCameraReady) { renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32); - mainCamera.targetTexture = renderTextureTarget; + cam.targetTexture = renderTextureTarget; } switch (view_mode) { @@ -696,7 +792,7 @@ private void SetTextures(sl.ZEDCamera zedCamera,sl.VIEW_MODE view_mode) depth = zedCamera.CreateTextureMeasureType(sl.MEASURE.DEPTH_RIGHT, resolution); } - else + else //This camera is not for an HMD. It's likely part of the ZED_Rig_Mono or ZED_GreenScreen prefab. { side = 0; switch (view_mode) { @@ -717,12 +813,12 @@ private void SetTextures(sl.ZEDCamera zedCamera,sl.VIEW_MODE view_mode) } /// - /// To enable/disable keyword for the material of the first pass + /// Enables/disables keywords for the material used in the first pass, when in forward rendering. /// - /// - /// + /// New state of the keyword. + /// Keyword's name. /// - public bool ManageKeyWordForwardMat(bool enable, string name) + public bool ManageKeywordForwardMat(bool enable, string name) { if (forwardMat) { @@ -741,7 +837,13 @@ public bool ManageKeyWordForwardMat(bool enable, string name) return false; } - public bool ManageKeyWordDefferedMat(bool enable, string name) + /// + /// Enables/disables keywords for the material used in the first pass, when in deferred rendering. + /// + /// New state of the keyword. + /// Keyword's name. + /// + public bool ManageKeywordDeferredMat(bool enable, string name) { if (deferredMat) { @@ -760,7 +862,13 @@ public bool ManageKeyWordDefferedMat(bool enable, string name) return false; } - public bool ManageKeyWordPipe(bool enable, string name) + /// + /// Enables/disables keywords for the final display material. + /// + /// New state of the keyword. + /// Keyword's name. + /// + public bool ManageKeywordPipe(bool enable, string name) { if (matRGB) { @@ -779,24 +887,31 @@ public bool ManageKeyWordPipe(bool enable, string name) return false; } + + //Variables to get information about the lights. + /// - /// Variables to get some informations about the lights + /// How many point lights are currently being rendered on the real world by this camera. Excludes ones filtered out by distance. /// [HideInInspector] public int numberPointLights; + + /// + /// How many spotlights are currently being rendered on the real world by this camera. Excludes ones filtered out by distance. + /// [HideInInspector] public int numberSpotLights; bool ghasShadows = false; /// - /// Update the lights information and send them to the shader + /// Updates lighting information, packages them into ComputeBuffers and sends them to the shader. /// void UpdateLights() { bool hasShadows = false; int pointLightIndex = 0; - int spotLighIndex = 0; + int spotLightIndex = 0; bounds.center = transform.position; foreach (ZEDLight zed_light in ZEDLight.s_lights) @@ -806,12 +921,12 @@ void UpdateLights() if (light.type == LightType.Directional || Vector3.Distance(bounds.center, light.transform.position) < (light.range + bounds.extents.x)) { - //Desactivate all shadows from point light and spot light, they are not currently supported + //Deactivate all shadows from point light and spotlights as they are not currently supported. if (light.type != LightType.Directional) { light.shadows = LightShadows.None; } - if (zed_light.IsEnabled() && ((pointLightIndex + spotLighIndex) < NUMBER_LIGHTS_MAX || light.type == LightType.Directional)) + if (zed_light.IsEnabled() && ((pointLightIndex + spotLightIndex) < NUMBER_LIGHTS_MAX || light.type == LightType.Directional)) { if (light.type == LightType.Point) { @@ -830,13 +945,13 @@ void UpdateLights() else if (light.type == LightType.Spot) { - if (spotLighIndex < NUMBER_SPOT_LIGHT_MAX) + if (spotLightIndex < NUMBER_SPOT_LIGHT_MAX) { - spotLights[spotLighIndex].color = light.color * light.intensity; - spotLights[spotLighIndex].position = light.gameObject.transform.position; - spotLights[spotLighIndex].direction = new Vector4(light.gameObject.transform.forward.normalized.x, light.gameObject.transform.forward.normalized.y, light.gameObject.transform.forward.normalized.z, Mathf.Cos((light.spotAngle / 2.0f) * Mathf.Deg2Rad)); - spotLights[spotLighIndex].parameters = new Vector4(light.spotAngle, light.intensity, 1.0f / light.range, zed_light.interiorCone); - spotLighIndex++; + spotLights[spotLightIndex].color = light.color * light.intensity; + spotLights[spotLightIndex].position = light.gameObject.transform.position; + spotLights[spotLightIndex].direction = new Vector4(light.gameObject.transform.forward.normalized.x, light.gameObject.transform.forward.normalized.y, light.gameObject.transform.forward.normalized.z, Mathf.Cos((light.spotAngle / 2.0f) * Mathf.Deg2Rad)); + spotLights[spotLightIndex].parameters = new Vector4(light.spotAngle, light.intensity, 1.0f / light.range, zed_light.interiorCone); + spotLightIndex++; } } else if (light.type == LightType.Directional) @@ -844,12 +959,12 @@ void UpdateLights() hasShadows = light.shadows != LightShadows.None && QualitySettings.shadows != ShadowQuality.Disable; directionalLightData[0] = new Vector4(light.gameObject.transform.forward.normalized.x, light.gameObject.transform.forward.normalized.y, light.gameObject.transform.forward.normalized.z, 0); directionalLightData[1] = light.color * light.intensity; - // Copy the shadows from the directional light, If not no shadows in transparent mode + // Copy the shadows from the directional light. If not, no shadows in transparent mode. if (light.commandBufferCount == 0) { forwardMat.SetInt("_HasShadows", System.Convert.ToInt32(light.shadows != LightShadows.None)); - // Copy the shadows from the directional light, If not no shadows in transparent mode + // Copy the shadows from the directional light. If not, no shadows in transparent mode. if (light.commandBufferCount == 0) { CommandBuffer lightBuffer = new CommandBuffer(); @@ -864,10 +979,10 @@ void UpdateLights() } } } - //Upload the new Data - if (computeBuffePointLight != null) + //Send the new light data to the final display material. + if (computeBufferPointLight != null) { - computeBuffePointLight.SetData(pointLights); + computeBufferPointLight.SetData(pointLights); } if (computeBufferSpotLight != null) { @@ -875,53 +990,55 @@ void UpdateLights() } numberPointLights = pointLightIndex; - numberSpotLights = spotLighIndex; + numberSpotLights = spotLightIndex; if (matRGB != null) { - //Add the command buffer to get shadows only if a directional light creates shadows + //Add the command buffer to get shadows only if a directional light creates shadows. if (hasShadows != ghasShadows) { ghasShadows = hasShadows; Shader.SetGlobalInt("_HasShadows", System.Convert.ToInt32(ghasShadows)); - mainCamera.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); if (hasShadows) { - mainCamera.AddCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); } } - //Send the number of pointLights/SpotLights to the shader + //Send the number of point lights/spotlights to the shader. matRGB.SetInt(numberPointLightsID, pointLightIndex); - matRGB.SetInt(numberSpotLightsID, spotLighIndex); + matRGB.SetInt(numberSpotLightsID, spotLightIndex); } matRGB.SetVectorArray("ZED_directionalLight", directionalLightData); } /// - /// Get back the FOV from the Projection matrix, to bypass a round number + /// Gets the vertical field of view from the given projection matrix, to bypass a round number. /// - /// + /// Projection matrix from a camera. /// float GetFOVYFromProjectionMatrix(Matrix4x4 projection) { return Mathf.Atan(1 / projection[1, 1]) * 2.0f; } + + /// + /// Gets the horizontal field of view from the given projection matrix. + /// + /// Projection matrix from a camera. + /// float GetFOVXFromProjectionMatrix(Matrix4x4 projection) { return Mathf.Atan(1 / projection[0, 0]) * 2.0f; } - - - - /// - /// Scale a screen in front of the camera, where all the textures will be rendered. + /// Scales the canvas in front of the camera so that it fills the whole screen exactly. /// - /// - /// + /// Canvas object. + /// Camera's vertical field of view. private void scale(GameObject screen, float fov) { float height = Mathf.Tan(0.5f * fov) * Vector3.Distance(screen.transform.localPosition, Vector3.zero) * 2; @@ -939,9 +1056,9 @@ private void scaleXY(GameObject screen, float fovH,float fovV) void OnApplicationQuit() { - if (computeBuffePointLight != null) + if (computeBufferPointLight != null) { - computeBuffePointLight.Release(); + computeBufferPointLight.Release(); } if (computeBufferSpotLight != null) @@ -955,6 +1072,9 @@ void OnApplicationQuit() } } + /// + /// Updates the output size to fit the window at 16:9 and the bounds for light filtering, and calculates the lighting. + /// void Update() { if(aspectRatio != null) @@ -968,21 +1088,31 @@ void Update() UpdateLights(); } + if(ZEDManager.Instance.IsZEDReady && (cam.nearClipPlane != nearplane || cam.farClipPlane != farplane)) + { + SetProjection(nearplane, farplane); //If the camera's near/far planes changed, update the matrix. + } + #if UNITY_EDITOR - if (actualRenderingPath != RenderingPath.VertexLit && mainCamera.actualRenderingPath != actualRenderingPath) + if (actualRenderingPath != RenderingPath.VertexLit && cam.actualRenderingPath != actualRenderingPath) { - ConfigureLightAndShadow(mainCamera.actualRenderingPath); + ConfigureLightAndShadow(cam.actualRenderingPath); } #endif } - /// - /// Used by the ZEDMeshRenderer/ZEDPlaneRenderer to overlay chunks/plane on the images + /// Used by the ZEDMeshRenderer/ZEDPlaneRenderer to draw chunks/planes onto the final images. /// private RenderTexture textureMapping; + + /// + /// Sets the RenderTexture that gets blended into the final result, if using Plane Detection or Spatial Mapping. + /// ZEDPlaneRenderer and ZEDMeshRenderer call this with the RenderTextures to which they render each frame. + /// + /// public void SetTextureOverlayMapping(RenderTexture texture) { textureMapping = texture; @@ -990,20 +1120,24 @@ public void SetTextureOverlayMapping(RenderTexture texture) } /// - /// Where the post process occurs + /// Where the post-processing occurs. + /// Called by Unity whenever the attached Camera renders an image. /// /// /// private void OnRenderImage(RenderTexture source, RenderTexture destination) { - if (ZEDSpatialMapping.display) { + if (ZEDSpatialMapping.display) //If displaying a mesh from spatial mapping, blend the wireframe into the image. + { RenderTexture tmpSource = RenderTexture.GetTemporary (source.width, source.height, source.depth, source.format, RenderTextureReadWrite.sRGB); Graphics.Blit (source, tmpSource); blender.SetInt ("_IsTextured", 0); blender.SetInt ("_IsPlaneRender", 0); //set Rendering mode for mapping / no texture Graphics.Blit (tmpSource, destination, blender); RenderTexture.ReleaseTemporary (tmpSource); - } else if (ZEDPlaneDetectionManager.isDisplay) { + } + else if (ZEDPlaneDetectionManager.isDisplay) //If displaying planes from plane detection, blend wireframes into the image. + { RenderTexture tmpSource = RenderTexture.GetTemporary (source.width, source.height, source.depth, source.format, RenderTextureReadWrite.sRGB); Graphics.Blit (source, tmpSource); blender.SetInt ("_IsTextured", 0); @@ -1011,10 +1145,9 @@ private void OnRenderImage(RenderTexture source, RenderTexture destination) Graphics.Blit (tmpSource, destination, blender); RenderTexture.ReleaseTemporary (tmpSource); } - else + else { - //Blit issue under opengl in standalone application. Post process is desactivated - if (ARpostProcessing && mask != null && zedCamera.IsCameraReady) + if (ARpostProcessing && mask != null && zedCamera.IsCameraReady) //Apply post-processing, if enabled. { if (actualRenderingPath == RenderingPath.DeferredShading) @@ -1026,11 +1159,11 @@ private void OnRenderImage(RenderTexture source, RenderTexture destination) Graphics.SetRenderTarget(buffer); GL.Clear(false, true, new Color(0, 0, 0, 0)); // clear the full RT - //To keep the stencil in post process + //To keep the stencil in post-processing, since Graphics.Blit normally clears it. Graphics.SetRenderTarget(buffer.colorBuffer, source.depthBuffer); Graphics.Blit(source, matStencilToMask); - //Compose the second mask get in the forward pass. The shader should set the stencil to 148 + //Compose the second mask retrieved in the forward pass. The shader should set the stencil to 148. Graphics.Blit(mask, bluredMask); matComposeMask.SetTexture("_Mask", bluredMask); Graphics.Blit(buffer, mask, matComposeMask); @@ -1040,14 +1173,14 @@ private void OnRenderImage(RenderTexture source, RenderTexture destination) RenderTexture.ReleaseTemporary(buffer); RenderTexture.ReleaseTemporary(bluredMask); } - else + else //Forward path. { RenderTexture bluredMask = RenderTexture.GetTemporary(mask.width, mask.height, mask.depth, mask.format); ApplyPostProcess(source, destination, bluredMask); RenderTexture.ReleaseTemporary(bluredMask); } } - else + else //Not using post-processing. { Graphics.Blit(source, destination); } @@ -1055,11 +1188,11 @@ private void OnRenderImage(RenderTexture source, RenderTexture destination) } /// - /// Post process pipeline + /// Apply post-processing effects to the given RenderTexture. /// - /// - /// - /// + /// Source RenderTexture. + /// Destination RenderTexture. + /// Mask used to apply blurring effects. private void ApplyPostProcess(RenderTexture source, RenderTexture destination, RenderTexture bluredMask) { RenderTexture tempDestination = RenderTexture.GetTemporary(source.width, source.height, source.depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); @@ -1074,25 +1207,50 @@ private void ApplyPostProcess(RenderTexture source, RenderTexture destination, R } + /// + /// Assigns the projection matrix from the ZED to this camera with the specified near/far planes. + /// + /// Adjusts the matrix values from a copy rather than reassigning them in ZEDCamera to avoid getting applied + /// to all copies of the camera. + /// + ///Desired near plane distance. + ///Desired far plane distance. + private void SetProjection(float near = 0.1f, float far = 500f) + { + //float near = mainCamera.nearClipPlane; + //float far = mainCamera.farClipPlane; + + Matrix4x4 newmat = zedCamera.Projection; + newmat[2, 2] = -(far + near) / (far - near); + newmat[2, 3] = -(2.0f * far * near) / (far - near); + cam.projectionMatrix = newmat; + + nearplane = near; + farplane = far; + } + + /// Forces the ZED's image to be displayed at a 16:9 ratio, regardless of the window's aspect ratio. + /// This is why the image doesn't stretch when the Game window in the editor is set to Free Aspet. + /// public class WindowAspectRatio { /// - /// Current screen width + /// Current screen width. /// private int ScreenSizeX = 0; /// - /// Current screen height + /// Current screen height. /// private int ScreenSizeY = 0; /// - /// Camera to set to 16:9 + /// Camera to set to 16:9. /// private Camera cam; /// - /// Aspect ratio targeted + /// Aspect ratio targeted. /// private const float TARGET_ASPECT = 16.0f / 9.0f; @@ -1105,7 +1263,7 @@ public WindowAspectRatio(Camera camera) } /// - /// Create a custom camera to render black bars + /// Create a custom hidden camera to render black bars in the background. /// /// private GameObject CreateCamera() @@ -1128,10 +1286,9 @@ private GameObject CreateCamera() } - - /// - /// Rescale the view port of the current camera + /// Rescale the view port of the current camera to keep the 16:9 aspect ratio. + /// This is called on start and updated each frame. /// private void RescaleCamera() { @@ -1141,7 +1298,7 @@ private void RescaleCamera() float windowaspect = (float)Screen.width / (float)Screen.height; float scaleheight = windowaspect / TARGET_ASPECT; - if (scaleheight < 1.0f) + if (scaleheight < 1.0f) //Height is too large. Shrink it, adding letterboxes to the top and bottom. { Rect rect = cam.rect; @@ -1150,9 +1307,9 @@ private void RescaleCamera() rect.x = 0; rect.y = (1.0f - scaleheight) / 2.0f; - cam.rect = rect; + //cam.rect = rect; } - else // add pillarbox + else //Height is too small. Reduce width, adding pillarboxes to the sides. { float scalewidth = 1.0f / scaleheight; @@ -1171,10 +1328,14 @@ private void RescaleCamera() } + /// + /// Calls RescaleCamera(). Called in ZEDRenderingPlane's Update() function. + /// public void Update() { RescaleCamera(); } + } } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs index 9c591ed3..53f60155 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs @@ -1,94 +1,97 @@ //======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// ##DEPRECATED + using UnityEngine; /// -/// Overhead to control SteamVR and Oculus in the same way +/// Interface for handling SteamVR and Oculus tracked controllers in the same way. +/// Implemented in ZEDSteamVRControllerManager and ZEDOculusControllerManager. /// -namespace sl +public interface ZEDControllerManager { /// - /// Overhead on the button - /// - public enum CONTROLS_BUTTON - { - THREE, - ONE, - PRIMARY_THUBMSTICK, - SECONDARY_THUMBSTICK - } - - /// - /// Overhead on the trackpad and sticks - /// - public enum CONTROLS_AXIS2D - { - PRIMARY_THUBMSTICK, - SECONDARY_THUMBSTICK - } - - /// - /// Overhead on the triggers - /// - public enum CONTROLS_AXIS1D - { - PRIMARY_INDEX_TRIGGER, - SECONDARY_INDEX_TRIGGER, - PRIMARY_HAND_TRIGGER, - SECONDARY_HAND_TRIGGER - } -} - -public interface ZEDControllerManager { - - /// - /// Checks if pads are init + /// Whether controllers have been initialized. /// bool PadsAreInit { get;} /// - /// Checks if a button is down + /// Checks if a button is down. /// - /// - /// + /// Button to check. + /// ID of the controller to check. /// - bool GetDown(sl.CONTROLS_BUTTON button, int idPad = -1); + bool GetDown(sl.CONTROLS_BUTTON button, int controllerid = -1); /// - /// Checks if a trigger is down + /// Checks if a trigger is down. /// - /// - /// + /// Trigger to check. + /// ID of the controller to check. /// - float GetHairTrigger(sl.CONTROLS_AXIS1D button, int idPad = -1); + float GetHairTrigger(sl.CONTROLS_AXIS1D button, int controllerID = -1); /// - /// Gets the ID of the right controller + /// Gets the ID of the right controller. /// /// int GetRightIndex(); /// - /// Gets the ID of the left controller + /// Gets the ID of the left controller. /// /// int GetLeftIndex(); /// - /// Get the local position of a controller + /// Gets the local position of a controller. /// /// /// Vector3 GetPosition(int IDPad); /// - /// Load the index according to the calibration tool + /// Loads the index of a controller according to files created from the ZED calibration tool. /// /// void LoadIndex(string path); /// - /// Gets the current ZEDHolder + /// Gets the index of the current ZEDHolder object. /// int ControllerIndexZEDHolder { get; } } + +namespace sl +{ + /// + /// VR controller button press sources. + /// + public enum CONTROLS_BUTTON + { + THREE, + ONE, + PRIMARY_THUMBSTICK, + SECONDARY_THUMBSTICK + } + + /// + /// VR controller trackpad/analog stick movement sources. + /// + public enum CONTROLS_AXIS2D + { + PRIMARY_THUBMSTICK, + SECONDARY_THUMBSTICK + } + + /// + /// VR controller trigger movement sources. + /// + public enum CONTROLS_AXIS1D + { + PRIMARY_INDEX_TRIGGER, + SECONDARY_INDEX_TRIGGER, + PRIMARY_HAND_TRIGGER, + SECONDARY_HAND_TRIGGER + } +} diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs index 2e1969f7..78c52729 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs @@ -7,11 +7,27 @@ using UnityEditor; #endif +/// +/// Causes the GameObject it's attached to to position itself where a tracked VR object is, such as +/// a Touch controller or Vive Tracker, but compensates for the ZED's latency. This way, virtual +/// controllers don't move ahead of its real-world image. +/// This is done by logging position data from the VR SDK in use (Oculus or OpenVR/SteamVR) each frame, but only +/// applying that position data to this transform after the delay in the latencyCompensation field. +/// Used in the ZED GreenScreen, Drone Shooter, Movie Screen, Planetarium and VR Plane Detection example scenes. +/// public class ZEDControllerTracker : MonoBehaviour { - private string loadedDevice = ""; + /// + /// Type of VR SDK loaded. 'Oculus', 'OpenVR' or empty. + /// + private string loadeddevice = ""; -#if ZED_STEAM_VR +#if ZED_STEAM_VR //Only enabled if the SteamVR Unity plugin is detected. + + /// + /// Enumerated version of the uint index SteamVR assigns to each device. + /// Converted from OpenVR.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole). + /// public enum EIndex { None = -1, @@ -36,19 +52,29 @@ public enum EIndex public EIndex index = EIndex.None; /// - /// Timers between each checks, to registers new pads + /// How long since we've last checked OpenVR for the specified device. + /// Incremented by Time.deltaTime each frame and reset when it reached timerMaxSteamVR. /// - private float timerVive = 0.0f; - private float timerMaxVive = 1.0f; - private devices oldDevice; + private float timerSteamVR = 0.0f; + + /// + /// How many seconds to wait between checking if the specified device is present in OpenVR. + /// The check is performed when timerSteamVR reaches this number, unless we've already retrieved the device index. + /// + private float timerMaxSteamVR = 1.0f; + private Devices oldDevice; #endif /// - /// Per each ID, contains the list of the position of each controller, used to delayed their tracking + /// Per each tracked object ID, contains a list of their recent positions. + /// Used to look up where OpenVR says a tracked object was in the past, for latency compensation. /// public Dictionary> poseData = new Dictionary>(); - public enum devices + /// + /// Types of tracked devices. + /// + public enum Devices { RightController, LeftController, @@ -58,32 +84,44 @@ public enum devices #endif Hmd, }; - [Tooltip("List of trackable devices that can be selected.")] - public devices deviceToTrack; - [Tooltip("Latency to be applied on the movement of this tracked object, to match the camera frequency.")] + /// + /// Type of trackable device that should be tracked. + /// + [Tooltip("Type of trackable device that should be tracked.")] + public Devices deviceToTrack; + + /// + /// Latency in milliseconds to be applied on the movement of this tracked object, so that virtual controllers don't + /// move ahead of their real-world image. + /// + [Tooltip("Latency in milliseconds to be applied on the movement of this tracked object, so that virtual controllers don't" + + " move ahead of their real-world image.")] [Range(0, 200)] - public int _latencyCompensation = 78; + public int latencyCompensation = 78; /// - /// The Serial number of the controller which is holding the ZED. + /// The Serial number of the controller/tracker to be tracked. + /// If specified, it will override the device returned using the 'Device to Track' selection. + /// Useful for forcing a specific device to be tracked, instead of the first left/right/Tracker object found. /// If Null, then there's no calibration to be applied to this script. /// If NONE, the ZEDControllerOffset failed to find any calibration file. /// If S/N is present, then this script will calibrate itself to track the correct device, if that's not the case already. + /// Note that ZEDOffsetController will load this number from a GreenScreen calibration file, if present. /// + [Tooltip("The Serial number of the controller/tracker to be tracked." + + " If specified, overrides the 'Device to Track' selection.")] public string SNHolder = ""; /// - /// Awake is used to initialize any variables or game state before the game starts. + /// Sets up the timed pose dictionary and identifies the VR SDK being used. /// void Awake() { - //Reseting the dictionary. - poseData.Clear(); - //Creating our element with its key and value. - poseData.Add(1, new List()); + poseData.Clear(); //Reset the dictionary. + poseData.Add(1, new List()); //Create the list within the dictionary with its key and value. //Looking for the loaded device - loadedDevice = UnityEngine.VR.VRSettings.loadedDeviceName; + loadeddevice = UnityEngine.VR.VRSettings.loadedDeviceName; } /// @@ -94,54 +132,54 @@ void Awake() void Update() { -#if ZED_OCULUS +#if ZED_OCULUS //Used only if the Oculus Integration plugin is detected. //Check if the VR headset is connected. - if (OVRManager.isHmdPresent && loadedDevice == "Oculus") + if (OVRManager.isHmdPresent && loadeddevice == "Oculus") { if (OVRInput.GetConnectedControllers().ToString() == "Touch") { //Depending on which tracked device we are looking for, start tracking it. - if (deviceToTrack == devices.LeftController) //Track the Left Oculus Controller. + if (deviceToTrack == Devices.LeftController) //Track the Left Oculus Controller. RegisterPosition(1, OVRInput.GetLocalControllerPosition(OVRInput.Controller.LTouch), OVRInput.GetLocalControllerRotation(OVRInput.Controller.LTouch)); - if (deviceToTrack == devices.RightController) //Track the Right Oculus Controller. + if (deviceToTrack == Devices.RightController) //Track the Right Oculus Controller. RegisterPosition(1, OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch), OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch)); - if (deviceToTrack == devices.Hmd) //Track the Oculus Hmd. + if (deviceToTrack == Devices.Hmd) //Track the Oculus Hmd. RegisterPosition(1, UnityEngine.VR.InputTracking.GetLocalPosition(UnityEngine.VR.VRNode.CenterEye), UnityEngine.VR.InputTracking.GetLocalRotation(UnityEngine.VR.VRNode.CenterEye)); - //Taking our saved positions, and applying a delay before assigning it to our Transform. + //Use our saved positions to apply a delay before assigning it to this object's Transform. if (poseData.Count > 0) { sl.Pose p; - //Delaying the saved values inside GetValuePosition() by a factor of latencyCompensation to the millisecond. - p = GetValuePosition(1, (float)(_latencyCompensation / 1000.0f)); + + //Delay the saved values inside GetValuePosition() by a factor of latencyCompensation in milliseconds. + p = GetValuePosition(1, (float)(latencyCompensation / 1000.0f)); transform.position = p.translation; //Assign new delayed Position transform.rotation = p.rotation; //Assign new delayed Rotation. } } } - //Enabling the updates of the internal state of OVRInput. + //Enable updating the internal state of OVRInput. OVRInput.Update(); #endif #if ZED_STEAM_VR - //Timer for checking on devices - timerVive += Time.deltaTime; + timerSteamVR += Time.deltaTime; //Increment timer for checking on devices - if (timerVive <= timerMaxVive) + if (timerSteamVR <= timerMaxSteamVR) return; - timerVive = 0f; + timerSteamVR = 0f; //Checks if a device has been assigned - if (index == EIndex.None && loadedDevice == "OpenVR") + if (index == EIndex.None && loadeddevice == "OpenVR") { if (BIsManufacturerController("HTC") || BIsManufacturerController("Oculus")) { //We look for any device that has "tracker" in its 3D model mesh name. - //We're doing this since the device ID changes based on how many devices are connected to Steam VR. - //This way if there's no controllers or just one, it's going to get the right ID for the Tracker. - if (deviceToTrack == devices.ViveTracker) + //We're doing this since the device ID changes based on how many devices are connected to SteamVR. + //This way, if there's no controllers or just one, it's going to get the right ID for the Tracker. + if (deviceToTrack == Devices.ViveTracker) { var error = ETrackedPropertyError.TrackedProp_Success; for (uint i = 0; i < 16; i++) @@ -157,34 +195,34 @@ void Update() } //Looks for a device with the role of a Right Hand. - if (deviceToTrack == devices.RightController) + if (deviceToTrack == Devices.RightController) { index = (EIndex)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand); } //Looks for a device with the role of a Left Hand. - if (deviceToTrack == devices.LeftController) + if (deviceToTrack == Devices.LeftController) { index = (EIndex)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand); } - //Assigns the Hmd - if (deviceToTrack == devices.Hmd) + //Assigns the HMD. + if (deviceToTrack == Devices.Hmd) { index = EIndex.Hmd; } } - //Display Warning if there was supposed to be a calibration file, and none was found. + //Display a warning if there was supposed to be a calibration file, and none was found. if (SNHolder.Equals("NONE")) { Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.PAD_CAMERA_CALIBRATION_NOT_FOUND)); } - else if (SNHolder != null && index != EIndex.None) + else if (SNHolder != null && index != EIndex.None) // { //If the Serial number of the Calibrated device isn't the same as the current tracked device by this script... if (!SteamVR.instance.GetStringProperty(Valve.VR.ETrackedDeviceProperty.Prop_SerialNumber_String, (uint)index).Contains(SNHolder)) { - Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.PAD_CAMERA_CALIBRATION_MISMATCH) + SNHolder); + Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.PAD_CAMERA_CALIBRATION_MISMATCH) + " Serial Number: " + SNHolder); //... then look for that device through all the connected devices. for (int i = 0; i < 16; i++) { @@ -194,16 +232,16 @@ void Update() index = (EIndex)i; string deviceRole = OpenVR.System.GetControllerRoleForTrackedDeviceIndex((uint)index).ToString(); if (deviceRole.Equals("RightHand")) - deviceToTrack = devices.RightController; + deviceToTrack = Devices.RightController; else if (deviceRole.Equals("LeftHand")) - deviceToTrack = devices.LeftController; + deviceToTrack = Devices.LeftController; else if (deviceRole.Equals("Invalid")) { var error = ETrackedPropertyError.TrackedProp_Success; var result = new System.Text.StringBuilder((int)64); OpenVR.System.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, result, 64, ref error); if (result.ToString().Contains("tracker")) - deviceToTrack = devices.ViveTracker; + deviceToTrack = Devices.ViveTracker; } Debug.Log("A connected device with the correct Serial Number was found, and assigned to " + this + " the correct device to track."); break; @@ -221,9 +259,13 @@ void Update() } #if ZED_STEAM_VR + /// + /// Whether a given set of poses is currently valid - contains at least one pose and attached to an actual device. + /// public bool isValid { get; private set; } + /// - /// Tracking the devices for SteamVR and applying a delay. + /// Track the devices for SteamVR and applying a delay. /// private void OnNewPoses(TrackedDevicePose_t[] poses) { @@ -249,15 +291,22 @@ private void OnNewPoses(TrackedDevicePose_t[] poses) var pose = new SteamVR_Utils.RigidTransform(poses[i].mDeviceToAbsoluteTracking); //Saving those values. RegisterPosition(1, pose.pos, pose.rot); - //Delaying the saved values inside GetValuePosition() by a factor of latencyCompensation to the millisecond. - sl.Pose p = GetValuePosition(1, (float)(_latencyCompensation / 1000.0f)); + + //Delay the saved values inside GetValuePosition() by a factor of latencyCompensation in milliseconds. + sl.Pose p = GetValuePosition(1, (float)(latencyCompensation / 1000.0f)); transform.localPosition = p.translation; transform.localRotation = p.rotation; } + /// + /// Reference to the Action that's called when new controller/tracker poses are available. + /// SteamVR_Events.Action newPosesAction; + /// + /// Constructor that makes sure newPosesAction gets assigned when this class is created. + /// ZEDControllerTracker() { newPosesAction = SteamVR_Events.NewPosesAction(OnNewPoses); @@ -281,6 +330,12 @@ void OnDisable() isValid = false; } + /// + /// Checks if the tracked controller is made by the provided company. + /// Works by retrieving the manufacturer name from SteamVR and checking that it starts with the specified string. + /// + /// Manufacturer's name. Example: "HTC" + /// public bool BIsManufacturerController(string name) { System.Text.StringBuilder sbType = new System.Text.StringBuilder(1000); @@ -292,41 +347,44 @@ public bool BIsManufacturerController(string name) #endif /// - /// Compute the delayed position and rotation from history + /// Compute the delayed position and rotation from the history stored in the poseData dictionary. /// - /// + /// /// /// - private sl.Pose GetValuePosition(int indx, float timeDelay) + private sl.Pose GetValuePosition(int keyindex, float timeDelay) { sl.Pose p = new sl.Pose(); - if (poseData.ContainsKey(indx)) + if (poseData.ContainsKey(keyindex)) { //Get the saved position & rotation. - p.translation = poseData[indx][poseData[indx].Count - 1].position; - p.rotation = poseData[indx][poseData[indx].Count - 1].rotation; + p.translation = poseData[keyindex][poseData[keyindex].Count - 1].position; + p.rotation = poseData[keyindex][poseData[keyindex].Count - 1].rotation; float idealTS = (Time.time - timeDelay); - for (int i = 0; i < poseData[indx].Count; ++i) + for (int i = 0; i < poseData[keyindex].Count; ++i) { - if (poseData[indx][i].timestamp > idealTS) + if (poseData[keyindex][i].timestamp > idealTS) { int currentIndex = i; if (currentIndex > 0) { //Calculate the time between the pose and the delayed pose. - float timeBetween = poseData[indx][currentIndex].timestamp - poseData[indx][currentIndex - 1].timestamp; - float alpha = ((Time.time - poseData[indx][currentIndex - 1].timestamp) - timeDelay) / timeBetween; - //Lerping to the next position based on the time determied above. - Vector3 pos = Vector3.Lerp(poseData[indx][currentIndex - 1].position, poseData[indx][currentIndex].position, alpha); - Quaternion rot = Quaternion.Lerp(poseData[indx][currentIndex - 1].rotation, poseData[indx][currentIndex].rotation, alpha); - //Applies new values + float timeBetween = poseData[keyindex][currentIndex].timestamp - poseData[keyindex][currentIndex - 1].timestamp; + float alpha = ((Time.time - poseData[keyindex][currentIndex - 1].timestamp) - timeDelay) / timeBetween; + + //Lerp to the next position based on the time determined above. + Vector3 pos = Vector3.Lerp(poseData[keyindex][currentIndex - 1].position, poseData[keyindex][currentIndex].position, alpha); + Quaternion rot = Quaternion.Lerp(poseData[keyindex][currentIndex - 1].rotation, poseData[keyindex][currentIndex].rotation, alpha); + + //Apply new values. p = new sl.Pose(); p.translation = pos; p.rotation = rot; - //Removes used elements from dictionary. - poseData[indx].RemoveRange(0, currentIndex - 1); + + //Removes used elements from the dictionary. + poseData[keyindex].RemoveRange(0, currentIndex - 1); } return p; } @@ -336,32 +394,52 @@ private sl.Pose GetValuePosition(int indx, float timeDelay) } /// - /// Set the current tracking to a container + /// Set the current tracking to a container (TimedPoseData) to be stored in poseData and retrieved/applied after the latency period. /// - /// - /// - /// - private void RegisterPosition(int indx, Vector3 position, Quaternion rot) + /// Key value in the dictionary. + /// Tracked object's position from the VR SDK. + /// Tracked object's rotation from the VR SDK. + private void RegisterPosition(int keyindex, Vector3 position, Quaternion rot) { TimedPoseData currentPoseData = new TimedPoseData(); currentPoseData.timestamp = Time.time; currentPoseData.rotation = rot; currentPoseData.position = position; - poseData[indx].Add(currentPoseData); + poseData[keyindex].Add(currentPoseData); } /// - /// Structures used to delay the controllers + /// Structure used to hold the pose of a controller at a given timestamp. + /// This is stored in poseData with RegisterPosition() each time the VR SDK makes poses available. + /// It's retrieved with GetValuePosition() in Update() each frame. /// public struct TimedPoseData { + /// + /// Value from Time.time when the pose was collected. + /// public float timestamp; + + /// + /// Rotation of the tracked object as provided by the VR SDK. + /// public Quaternion rotation; + + /// + /// Position of the tracked object as provided by the VR SDK. + /// public Vector3 position; } } #if UNITY_EDITOR +/// +/// Custom editor for ZEDControllerTracker. +/// If no VR Unity plugin (Oculus Integration or SteamVR plugin) has been loaded by the ZED plugin but one is found, +/// presents a button to create project defines that tell ZED scripts that this plugin is loaded. +/// These defines (ZED_STEAM_VR and ZED_OCULUS) are used to allow compiling parts of ZED scripts that depend on scripts in these VR plugins. +/// Note that this detection will also be attempted any time an asset has been imported. See nested class AssetPostProcessZEDVR. +/// [CustomEditor(typeof(ZEDControllerTracker)), CanEditMultipleObjects] public class ZEDVRDependencies : Editor { @@ -369,7 +447,7 @@ public class ZEDVRDependencies : Editor static string defineName; static string packageName; - public override void OnInspectorGUI() + public override void OnInspectorGUI() //Called when the Inspector is visible. { if (CheckPackageExists("SteamVR")) { @@ -382,11 +460,11 @@ public override void OnInspectorGUI() packageName = "Oculus"; } - if (EditorPrefs.GetBool(packageName)) + if (EditorPrefs.GetBool(packageName)) //Has it been set? { DrawDefaultInspector(); } - else + else //No package loaded, but one has been detected. Present a button to load it. { GUILayout.Space(20); if (GUILayout.Button("Load " + packageName + " data")) @@ -403,13 +481,23 @@ public override void OnInspectorGUI() } } + /// + /// Finds if a folder in the project exists with the specified name. + /// Used to check if a plugin has been imported, as the relevant plugins are placed + /// in a folder named after the package. Example: "Assets/Oculus". + /// + /// Package name. + /// public static bool CheckPackageExists(string name) { string[] packages = AssetDatabase.FindAssets(name); return packages.Length != 0 && AssetDatabase.IsValidFolder("Assets/" + name); } - + /// + /// Activates a define tag in the project. Used to enable compiling sections of scripts with that tag enabled. + /// For instance, parts of this script under a #if ZED_STEAM_VR statement will be ignored by the compiler unless ZED_STEAM_VR is enabled. + /// public static void ActivateDefine() { EditorPrefs.SetBool(packageName, true); @@ -417,14 +505,14 @@ public static void ActivateDefine() string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone); if (defines.Length != 0) { - if (!defines.Contains(defineName)) + if (defineName != null && !defines.Contains(defineName)) { defines += ";" + defineName; } } else { - if (!defines.Contains(defineName)) + if (defineName != null && !defines.Contains(defineName)) { defines += defineName; } @@ -432,15 +520,19 @@ public static void ActivateDefine() PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, defines); } - - public static void DesactivateDefine() + /// + /// Removes a define tag from the project. + /// Called whenever a package is checked for but not found. + /// Removing the define tags will prevent compilation of code marked with that tag, like #if ZED_OCULUS. + /// + public static void DeactivateDefine() { EditorPrefs.SetBool(packageName, false); - + string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone); if (defines.Length != 0) { - if (defines.Contains(defineName)) + if (defineName != null && defines.Contains(defineName)) { defines = defines.Remove(defines.IndexOf(defineName), defineName.Length); @@ -453,9 +545,12 @@ public static void DesactivateDefine() PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, defines); } + /// + /// Inherits from UnityEditor.AssetPostProcessor to run ZED plugin-specific code whenever an asset is imported. + /// This code checks for the Oculus and SteamVR Unity packages, to activate or deactivate project define tags accordingly. + /// public class AssetPostProcessZEDVR : AssetPostprocessor { - static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { @@ -473,7 +568,7 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse } else { - DesactivateDefine(); + DeactivateDefine(); } } } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOculusControllerManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOculusControllerManager.cs index 41d0c25b..a303ef02 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOculusControllerManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOculusControllerManager.cs @@ -1,4 +1,5 @@ //======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// ##DEPRECATED using System.Collections; @@ -221,7 +222,7 @@ private OVRInput.Button ConvertToButton(sl.CONTROLS_BUTTON button) { case sl.CONTROLS_BUTTON.ONE: return OVRInput.Button.One; case sl.CONTROLS_BUTTON.THREE: return OVRInput.Button.Three; - case sl.CONTROLS_BUTTON.PRIMARY_THUBMSTICK: return OVRInput.Button.PrimaryThumbstick; + case sl.CONTROLS_BUTTON.PRIMARY_THUMBSTICK: return OVRInput.Button.PrimaryThumbstick; case sl.CONTROLS_BUTTON.SECONDARY_THUMBSTICK: return OVRInput.Button.SecondaryThumbstick; } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs index 15ccd18f..8cb269dd 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs @@ -1,4 +1,5 @@ //======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// ##DEPRECATED using UnityEngine; @@ -8,25 +9,39 @@ #endif /// -/// Enables to save/load the position of the ZED, is useful especially for the greenScreen +/// Saves and loads the pose of this object relative to its parent. +/// Used primarily when mounting the ZED to a tracked object (like a VR controller) for 3rd person mixed reality. +/// This way, you can calibrate its position/rotation to line up the real/virtual worlds, and hit Save. +/// It will automatically load a calibration in the future if it's found. +/// Note that if you used our beta tool for SteamVR calibration, this script will load that calibration automatically. /// public class ZEDOffsetController : MonoBehaviour { - /// - /// ZED pose file name + /// ZED offset file name. /// [SerializeField] public static string ZEDOffsetFile = "ZED_Position_Offset.conf"; + /// + /// Where to save the ZED offset file. + /// private string path = @"Stereolabs\steamvr"; - public ZEDControllerTracker padManager; + /// + /// The ZEDControllerTracker object in the scene from which we're offset. + /// This script checks this object, its parents and its children (in that order) for such a component. + /// + public ZEDControllerTracker controllerTracker; + /// + /// If the object is instantiated and ready to save/load an offset file. + /// Used by the custom Inspector editor to know if the Save/Load buttons should be pressable. + /// public bool isReady = false; /// - /// Save the position of the ZED + /// Save the local position/rotation of the ZED into an offset file. /// public void SaveZEDPos() { @@ -39,7 +54,7 @@ public void SaveZEDPos() string ry = "ry=" + transform.localRotation.eulerAngles.y.ToString() + " //Rotation y"; string rz = "rz=" + transform.localRotation.eulerAngles.z.ToString() + " //Rotation z"; - + //Write those values into the file. file.WriteLine(tx); file.WriteLine(ty); file.WriteLine(tz); @@ -55,21 +70,26 @@ public void SaveZEDPos() #if ZED_STEAM_VR - if (PadComponentExist()) + if (TrackerComponentExist()) { - string i = "indexController=" + (padManager.index > 0 ? SteamVR.instance.GetStringProperty(Valve.VR.ETrackedDeviceProperty.Prop_SerialNumber_String, (uint)padManager.index) : "NONE") + " //SN of the pad attached to the camera (NONE to set no pad on it)"; + //If using SteamVR, get the serial number of the tracked device, or write "NONE" to indicate we checked but couldn't find it. + //This is used by ZEDControllerManager later to know specifically which device the loaded offset has been calibrated to, in the event of multiple controllers/trackers. + string i = "indexController=" + (controllerTracker.index > 0 ? SteamVR.instance.GetStringProperty(Valve.VR.ETrackedDeviceProperty.Prop_SerialNumber_String, (uint)controllerTracker.index) : "NONE") + " //SN of the pad attached to the camera (NONE to set no pad on it)"; file.WriteLine(i); } #endif - - file.Close(); + file.Close(); //Finalize the new file. } } - public bool PadComponentExist() + /// + /// Whether there is a referenced ZEDControllerTracker object in this object, a parent, or a child. + /// + /// True if such a component exists and is used to handle the offset. + public bool TrackerComponentExist() { - if (padManager != null) + if (controllerTracker != null) return true; else return false; @@ -77,23 +97,31 @@ public bool PadComponentExist() private void OnEnable() { - LoadComponentPad(); + LoadTrackerComponent(); } - private void LoadComponentPad() + /// + /// Searched for a ZEDControllerTracker component in this object, its parents, and its children. + /// Sets the controllerTracker value to the first one it finds. + /// + private void LoadTrackerComponent() { - ZEDControllerTracker pad = GetComponent(); - if (pad == null) - pad = GetComponentInParent(); - if (pad == null) - pad = GetComponentInChildren(); - if (pad != null) - padManager = pad; + ZEDControllerTracker zct = GetComponent(); + if (zct == null) + zct = GetComponentInParent(); + if (zct == null) + zct = GetComponentInChildren(); + if (zct != null) + controllerTracker = zct; } - + + /// + /// Tries to find the relevant ZEDControllerTracker object, and loads the existing + /// offset file if there is one. + /// void Awake() { - LoadComponentPad(); + LoadTrackerComponent(); string folder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData); string specificFolder = Path.Combine(folder, @"Stereolabs\steamvr"); @@ -117,7 +145,7 @@ private void Update() } /// - /// Load the position of the ZED from a file + /// Loads the offset file and sets the local position/rotation to the loaded values. /// public void LoadZEDPos() { @@ -130,11 +158,11 @@ public void LoadZEDPos() } catch (System.Exception) { - padManager.SNHolder = "NONE"; + controllerTracker.SNHolder = "NONE"; } if (lines == null) { - padManager.SNHolder = "NONE"; + controllerTracker.SNHolder = "NONE"; return; } if (lines == null) return; @@ -174,11 +202,11 @@ public void LoadZEDPos() } else if(key == "indexController") { - LoadComponentPad(); + LoadTrackerComponent(); - if (PadComponentExist()) + if (TrackerComponentExist()) { - padManager.SNHolder = field; + controllerTracker.SNHolder = field; } } } @@ -187,6 +215,11 @@ public void LoadZEDPos() transform.localRotation = Quaternion.Euler(eulerRotation.x, eulerRotation.y, eulerRotation.z); } + /// + /// Creates a FileSystemWatcher that keeps track of the offset file, in case it + /// changes or moves. + /// + /// public void CreateFileWatcher(string path) { // Create a new FileSystemWatcher and set its properties. @@ -206,10 +239,15 @@ the renaming of files or directories. */ watcher.EnableRaisingEvents = true; } - // Define the event handlers. + /// + /// Event handler for when the offset file changes or moves. + /// Called by the FileSystemWatcher created in CreateFileWatcher(). + /// + /// + /// private void OnChanged(object source, FileSystemEventArgs e) { - if (PadComponentExist()) + if (TrackerComponentExist()) { LoadZEDPos(); } @@ -219,7 +257,11 @@ private void OnChanged(object source, FileSystemEventArgs e) #if UNITY_EDITOR - +/// +/// Custom editor for ZEDOffsetController, to define its Inspector layout. +/// Specifically, it doesn't draw public fields like normal but instead places Save/Load buttons +/// for the offset file that are only pressable during runtime. +/// [CustomEditor(typeof(ZEDOffsetController))] public class ZEDPositionEditor : Editor { @@ -231,7 +273,7 @@ public void OnEnable() } - public override void OnInspectorGUI() + public override void OnInspectorGUI() //Called when the Inspector GUI becomes visible, or changes at all. { GUILayout.Space(5); EditorGUILayout.BeginHorizontal(); @@ -240,11 +282,13 @@ public override void OnInspectorGUI() EditorGUILayout.BeginHorizontal(); GUI.enabled = positionManager.isReady; - if (GUILayout.Button("Save Camera Offset")) + GUIContent savecontent = new GUIContent("Save Offset", "Saves the object's local position/rotation to a text file to be loaded anytime in the future."); + if (GUILayout.Button(savecontent)) { positionManager.SaveZEDPos(); } - if (GUILayout.Button("Load Camera Offset")) + GUIContent loadcontent = new GUIContent("Load Offset", "Loads local position/rotation from an offset file previously saved, or created by the beta ZED calibration tool."); + if (GUILayout.Button(loadcontent)) { positionManager.LoadZEDPos(); } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDSteamVRControllerManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDSteamVRControllerManager.cs index 746a1d58..5fe846a4 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDSteamVRControllerManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDSteamVRControllerManager.cs @@ -1,4 +1,5 @@ //======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// ##DEPRECATED using System.Collections.Generic; using UnityEngine; @@ -657,7 +658,7 @@ private EVRButtonId ConvertToButton(sl.CONTROLS_BUTTON button) { case sl.CONTROLS_BUTTON.ONE: return model == HMD.OCULUS ? EVRButtonId.k_EButton_A : EVRButtonId.k_EButton_ApplicationMenu; case sl.CONTROLS_BUTTON.THREE: return EVRButtonId.k_EButton_ApplicationMenu; - case sl.CONTROLS_BUTTON.PRIMARY_THUBMSTICK: return EVRButtonId.k_EButton_SteamVR_Touchpad; + case sl.CONTROLS_BUTTON.PRIMARY_THUMBSTICK: return EVRButtonId.k_EButton_SteamVR_Touchpad; case sl.CONTROLS_BUTTON.SECONDARY_THUMBSTICK: return EVRButtonId.k_EButton_SteamVR_Touchpad; } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs index d2194b74..18a07eac 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs @@ -2,51 +2,107 @@ using System.Collections.Generic; using UnityEngine; +/// +/// Moves/rotates the attached object using the keyboard or, if the +/// Oculus/SteamVR plugins are imported, by buttons on the VR controllers. +/// To use VR controllers, you must also have a ZEDControllerTracker component in the scene +/// that's set to track the controller you want to use. +/// Used in the ZED Planetarium and Movie Screen example scenes to move the solar system/screen. +/// public class ZEDTransformController : MonoBehaviour { - public enum relativeMotion - { - Itself, - Camera - } + //Public variables + + /// + /// Rotational reference point for moving forward, backward, left, right, etc. + /// [Header("Object motion relative to:")] - public relativeMotion motion; + [Tooltip("Rotational reference point for moving forward, backward, left, right, etc.")] + public RelativeMotion motion; + + /// + /// Whether to rotate in the opposite direction specified, eg rotating 'right' means counter-clockwise. + /// + [Tooltip("Whether to rotate in the opposite direction specified, eg rotating 'right' means counter-clockwise.")] public bool invertRotation; - [Space(5)] - [Header("Input Mode")] - [Tooltip("If VR Controls are disabled, then the keyboard shortcuts will be applied.")] - public bool VRControls; - [Space(5)] - [Header("Motion Options.")] - //Public variables - public float MovementSpeed = 0.5F; - public float RotationSpeed = 0.5F; - public float ScaleSpeed = 0.25F; + /// + /// If true, the object will teleport to a meter in front of the ZED once it's finished initializing. + /// + [Tooltip("If true, the object will teleport to a meter in front of the ZED once it's finished initializing.")] + public bool repositionAtStart = true; + + /// + /// How fast the object moves/translates, in meters per second. + /// + [Space(5)] + [Header("Motion Options")] + [Tooltip("How fast the object moves/translates, in meters per second. ")] + public float movementSpeed = 0.5F; + + /// + /// How fast the object rotates, in revolutions per second. + /// + [Tooltip("How fast the object rotates, in revolutions per second.")] + public float rotationSpeed = 0.1f; + + /// + /// How quickly an object gets bigger or smaller. + /// Scale increases/decreases by this factor every second. + /// + [Tooltip("How quickly an object gets bigger or smaller. Scale increases/decreases by this factor every second.")] + public float scaleSpeed = 0.25F; + + /// + /// The largest amount to which the object can scale. + /// + [Tooltip("The largest amount to which the object can scale.")] public float maxScale = 2.0F; + + /// + /// The smallest amount down to which the object can scale. + /// + [Tooltip("The smallest amount down to which the object can scale. ")] public float minScale = 0.25F; + + /// + /// Optional reference to a light that is enabled only when moving. + /// Used in the ZED Movie Screen sample to project a light underneath the screen when moved. + /// + [Space(5)] + [Tooltip("Optional reference to a light that is enabled only when moving.")] public Light spotLight; //Private variables + + /// + /// List of all ZEDControllerTrackers in the scene. Used to get input in an SDK/agnostic way. + /// private List objectTrackers = new List(); - private float inputScale; - private float inputRotation; - private Camera LeftCamera; - private bool reposition = false; - private ZEDManager zManager; + + /// + /// Left Camera component in the ZED rig, that represents the ZED's left sensor. + /// Used when RelativeMotion is set to Camera for providing relative values. + /// + private Camera leftCamera; + + /// + /// Reference to the scene's ZEDManager component. + /// Used when RelativeMotion is set to Camera, for finding the current position of the ZED. + /// + private ZEDManager zedManager; + + /// + /// Whether the object is moving/translating. + /// private bool isMoving; private IEnumerator Start() { isMoving = false; - //Find the left camera object if we didn't assign it at start. - if (!LeftCamera) - { - zManager = ZEDManager.Instance; - LeftCamera = zManager.GetLeftCameraTransform().gameObject.GetComponent(); - } + zedManager = ZEDManager.Instance; - //Finding the available VR controllers and assigning them to our List. + //Find the available VR controllers and assigning them to our List. yield return new WaitForSeconds(1f); var trackers = FindObjectsOfType(); @@ -55,177 +111,162 @@ private IEnumerator Start() objectTrackers.Add(tracker); } -#if ZED_STEAM_VR - if (objectTrackers.Count > 0) - { - for (int i = 0; i < objectTrackers.Count; i++) - { - if (objectTrackers[i].index >= 0) - VRControls = true; - } - } -#endif - -#if ZED_OCULUS - if (OVRManager.isHmdPresent) + if (repositionAtStart) //If the user wants, move the object in front of the ZED once it's initialized. { - if (OVRInput.GetConnectedControllers().ToString() == "Touch") - VRControls = true; + ZEDManager.OnZEDReady += RepositionInFrontOfZED; } -#endif } private void Update() { - //Reposition the screen in front our the Camera when its ready - if (ZEDManager.Instance.IsZEDReady && reposition == false) - { - transform.position = ZEDManager.Instance.OriginPosition + ZEDManager.Instance.OriginRotation * (Vector3.forward); - Quaternion newRot = Quaternion.LookRotation(ZEDManager.Instance.OriginPosition - transform.position, Vector3.up); - transform.eulerAngles = new Vector3(0, newRot.eulerAngles.y + 180, 0); - reposition = true; - } - - Vector3 moveAxis = Vector3.zero; + Vector3 moveAxis = Vector3.zero; //Translation. Used by keyboard only. + float inputRotation = 0f; //Applied rotation, between -1 and 1. Cumulative between keyboard and controllers. + float inputScale = 0f; //Applied scale change, either -1, 0 or 1. Cumulative between keyboard and controllers. + //Keyboard inputs. if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.Q)) { - inputRotation = -1 * (RotationSpeed * 50) * Time.deltaTime; + inputRotation = -1 * (rotationSpeed * 360) * Time.deltaTime; } if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.E)) { - inputRotation = 1 * (RotationSpeed * 50) * Time.deltaTime; + inputRotation = 1 * (rotationSpeed * 360) * Time.deltaTime; } if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) { - moveAxis = Vector3.forward * MovementSpeed * Time.deltaTime; + moveAxis = Vector3.forward * movementSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S)) { - moveAxis = Vector3.back * MovementSpeed * Time.deltaTime; + moveAxis = Vector3.back * movementSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.A)) { - moveAxis = Vector3.left * MovementSpeed * Time.deltaTime; + moveAxis = Vector3.left * movementSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.D)) { - moveAxis = Vector3.right * MovementSpeed * Time.deltaTime; + moveAxis = Vector3.right * movementSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.R)) { - moveAxis = Vector3.up * MovementSpeed * Time.deltaTime; + moveAxis = Vector3.up * movementSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.F)) { - moveAxis = Vector3.down * MovementSpeed * Time.deltaTime; + moveAxis = Vector3.down * movementSpeed * Time.deltaTime; } Quaternion gravity = Quaternion.identity; - if (!VRControls) + + if (moveAxis != Vector3.zero) { - if (moveAxis != Vector3.zero) + isMoving = true; + if (motion == RelativeMotion.Itself) { - isMoving = true; - if(motion == relativeMotion.Itself) transform.Translate(moveAxis.x, moveAxis.y, moveAxis.z); - else if (motion == relativeMotion.Camera) - { - gravity = Quaternion.FromToRotation(zManager.GetZedRootTansform().up, Vector3.up); - transform.localPosition += zManager.GetLeftCameraTransform().right * moveAxis.x; - transform.localPosition += zManager.GetLeftCameraTransform().forward * moveAxis.z; - transform.localPosition += gravity * zManager.GetLeftCameraTransform().up * moveAxis.y; - } } - else + else if (motion == RelativeMotion.Camera) { - isMoving = false; + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += zedManager.GetLeftCameraTransform().right * moveAxis.x; + transform.localPosition += zedManager.GetLeftCameraTransform().forward * moveAxis.z; + transform.localPosition += gravity * zedManager.GetLeftCameraTransform().up * moveAxis.y; } - - if (Input.GetKey(KeyCode.Mouse0)) - inputScale = 1f; - else if (Input.GetKey(KeyCode.Mouse1)) - inputScale = -1f; } else { - if (zManager) - { -#if ZED_OCULUS - if(UnityEngine.VR.VRSettings.loadedDeviceName == "Oculus") - { - if (OVRInput.GetConnectedControllers().ToString() == "Touch") - { - if (objectTrackers.Count > 0) - { - moveAxis = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, OVRInput.Controller.RTouch); - inputRotation = moveAxis.x * RotationSpeed; + isMoving = false; + } - gravity = Quaternion.FromToRotation(zManager.GetZedRootTansform().up, Vector3.up); - transform.localPosition += gravity * zManager.GetLeftCameraTransform().up * moveAxis.y * MovementSpeed * Time.deltaTime; + if (Input.GetKey(KeyCode.Mouse0)) + inputScale = 1f; + else if (Input.GetKey(KeyCode.Mouse1)) + inputScale = -1f; - if (OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.RTouch) > 0.75f) - inputScale = 1f; - } - - if (objectTrackers.Count > 1) - { - moveAxis = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, OVRInput.Controller.LTouch); - if (moveAxis.x != 0 || moveAxis.y != 0) - { - isMoving = true; - gravity = Quaternion.FromToRotation(zManager.GetZedRootTansform().up, Vector3.up); - transform.localPosition += zManager.GetLeftCameraTransform().right * moveAxis.x * MovementSpeed * Time.deltaTime; - transform.localPosition += gravity * zManager.GetLeftCameraTransform().forward * moveAxis.y * MovementSpeed * Time.deltaTime; - } - else - isMoving = false; - - if (OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.LTouch) > 0.75f) - inputScale = -1f; - } - } + if (zedManager) + { +#if ZED_OCULUS + if (UnityEngine.VR.VRSettings.loadedDeviceName == "Oculus") + { + if (OVRInput.GetConnectedControllers().ToString() == "Touch") + { + Vector3 moveaxisoculus = new Vector3(); //Position change by controller. Added to keyboard version if both are applied. - OVRInput.Update(); - } -#endif -#if ZED_STEAM_VR - if (UnityEngine.VR.VRSettings.loadedDeviceName == "OpenVR") - { - //Looks for any input from this controller through SteamVR - if (objectTrackers.Count > 0 && objectTrackers[0].index >= 0) + if (objectTrackers.Count > 0) { - moveAxis = SteamVR_Controller.Input((int)objectTrackers[0].index).GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis0); - inputRotation = moveAxis.x * RotationSpeed; - gravity = Quaternion.FromToRotation(zManager.GetZedRootTansform().up, Vector3.up); - transform.localPosition += gravity * zManager.GetLeftCameraTransform().up * moveAxis.y * MovementSpeed * Time.deltaTime; + moveaxisoculus = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, OVRInput.Controller.RTouch); + inputRotation += moveaxisoculus.x * rotationSpeed * 360 * Time.deltaTime; + - if (objectTrackers[0].index > 0 && SteamVR_Controller.Input((int)objectTrackers[0].index).GetHairTrigger()) + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += gravity * zedManager.GetLeftCameraTransform().up * moveaxisoculus.y * movementSpeed * Time.deltaTime; + + if (OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.RTouch) > 0.75f) inputScale = 1f; } - if (objectTrackers.Count > 1 && objectTrackers[1].index >= 0) + if (objectTrackers.Count > 1) { - moveAxis = SteamVR_Controller.Input((int)objectTrackers[1].index).GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis0); - - if (moveAxis.x != 0 || moveAxis.y != 0) + moveaxisoculus = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, OVRInput.Controller.LTouch); + if (moveaxisoculus.x != 0 || moveaxisoculus.y != 0) { isMoving = true; - gravity = Quaternion.FromToRotation(zManager.GetZedRootTansform().up, Vector3.up); - transform.localPosition += zManager.GetLeftCameraTransform().right * moveAxis.x * MovementSpeed * Time.deltaTime; - transform.localPosition += gravity * zManager.GetLeftCameraTransform().forward * moveAxis.y * MovementSpeed * Time.deltaTime; + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += zedManager.GetLeftCameraTransform().right * moveaxisoculus.x * movementSpeed * Time.deltaTime; + transform.localPosition += gravity * zedManager.GetLeftCameraTransform().forward * moveaxisoculus.y * movementSpeed * Time.deltaTime; } else isMoving = false; - if (objectTrackers[1].index > 0 && SteamVR_Controller.Input((int)objectTrackers[1].index).GetHairTrigger()) + if (OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, OVRInput.Controller.LTouch) > 0.75f) inputScale = -1f; } } + + OVRInput.Update(); + } #endif +#if ZED_STEAM_VR + if (UnityEngine.VR.VRSettings.loadedDeviceName == "OpenVR") + { + Vector3 moveaxissteamvr = new Vector3(); //Position change by controller. Added to keyboard version if both are applied. + + //Looks for any input from this controller through SteamVR. + if (objectTrackers.Count > 0 && objectTrackers[0].index >= 0) + { + moveaxissteamvr = SteamVR_Controller.Input((int)objectTrackers[0].index).GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis0); + inputRotation += moveaxissteamvr.x * rotationSpeed * 360f * Time.deltaTime; + + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += gravity * zedManager.GetLeftCameraTransform().up * moveaxissteamvr.y * movementSpeed * Time.deltaTime; + + if (objectTrackers[0].index > 0 && SteamVR_Controller.Input((int)objectTrackers[0].index).GetHairTrigger()) + inputScale = 1f; + } + + if (objectTrackers.Count > 1 && objectTrackers[1].index >= 0) + { + moveaxissteamvr = SteamVR_Controller.Input((int)objectTrackers[1].index).GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis0); + + if (moveaxissteamvr.x != 0 || moveaxissteamvr.y != 0) + { + isMoving = true; + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += zedManager.GetLeftCameraTransform().right * moveaxissteamvr.x * movementSpeed * Time.deltaTime; + transform.localPosition += gravity * zedManager.GetLeftCameraTransform().forward * moveaxissteamvr.y * movementSpeed * Time.deltaTime; + } + else + isMoving = false; + + if (objectTrackers[1].index > 0 && SteamVR_Controller.Input((int)objectTrackers[1].index).GetHairTrigger()) + inputScale = -1f; + } } +#endif + } //Rotation @@ -236,14 +277,8 @@ private void Update() else transform.Rotate(0, -h, 0); - //Reset Rotation for next frame - inputRotation = 0f; - //Scale - float s = ScaleSpeed * (inputScale * Time.deltaTime); - - //Reset scale for next frame - inputScale = 0f; + float s = scaleSpeed * (inputScale * Time.deltaTime); transform.localScale = new Vector3(transform.localScale.x + s, transform.localScale.y + s, @@ -254,14 +289,20 @@ private void Update() else if (transform.localScale.x < minScale) transform.localScale = new Vector3(minScale, minScale, minScale); - //Enable/Disable light + //Enable/disable light if moving. if (spotLight != null) - EnableLights(); + { + SetMovementLight(); + } } - void EnableLights() + /// + /// Turns the optional spotLight on or off depending on if the object is moving/translating. + /// Also scales the light to match the object's own scale. + /// + void SetMovementLight() { - //Enable / Disable Light if there is any and the object is moving. + //Enable/disable Light if the object is moving. if (!spotLight.enabled && isMoving) { spotLight.enabled = true; @@ -271,7 +312,7 @@ void EnableLights() spotLight.enabled = false; } - //Scale Light with Object Size + //Scale light with object size. if (spotLight.enabled && spotLight.type == LightType.Spot) { spotLight.spotAngle = transform.localScale.x * 180 * 2; @@ -280,4 +321,24 @@ void EnableLights() spotLight.range = 2; } } + + /// + /// Repositions the object to a meter in front of the ZED. + /// Called by ZEDManager.OnZEDReady if repositionAtStart is enabled. + /// + void RepositionInFrontOfZED() + { + transform.position = ZEDManager.Instance.OriginPosition + ZEDManager.Instance.OriginRotation * (Vector3.forward); + Quaternion newRot = Quaternion.LookRotation(ZEDManager.Instance.OriginPosition - transform.position, Vector3.up); + transform.eulerAngles = new Vector3(0, newRot.eulerAngles.y + 180, 0); + } + + /// + /// Options for what movement will be relevant to. + /// + public enum RelativeMotion + { + Itself, //Relative to its own rotation, eg. moving forward moves where the object is facing. + Camera //Relative to the camera's rotation, eg. moving forward moves where the camera/player is facing. + } } \ No newline at end of file diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs index 6c9f01fb..f72acd3a 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs @@ -3,25 +3,28 @@ using UnityEngine; /// -/// Registers the light in a common structure and checks if the light can be displayed +/// Causes the attached Light component to cast light on the real world, if visible by the ZED. +/// Must be a point, spot, or directional light. Directional lights will also cast shadows on real objects. +/// Works by registering the Light component to a static list (contained within) that's checked by ZEDRenderingPlane. +/// For more information, see our Lighting guide: https://docs.stereolabs.com/mixed-reality/unity/lighting/ /// [RequireComponent(typeof(Light))] public class ZEDLight : MonoBehaviour { /// - /// Static structures shared among all the instances of ZEDLight + /// List of all ZEDLights in the scene. /// [HideInInspector] public static List s_lights = new List(); /// - /// Cached the light + /// Light component attached to this GameObject. /// [HideInInspector] public Light cachedLight; /// - /// Interior cone of the spot light. + /// Interior cone of the spotlight, if the Light is a spotlight. /// [HideInInspector] public float interiorCone = 0.1f; @@ -46,7 +49,8 @@ void OnDisable() /// - /// Checks if a light is enable or if it is lighting + /// Checks if a light is both enabled and has above-zero range and intensity. + /// Used by ZEDRenderingPlane to filter out lights that won't be visible. /// /// public bool IsEnabled() diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs index c4b54056..968ba4a1 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs @@ -3,23 +3,27 @@ using UnityEngine; /// -/// Create a mirror view and replace the view created by Unity +/// In AR mode, displays a full-screen, non-timewarped view of the scene for the editor's Game window. +/// Replaces Unity's default behavior of replicating the left eye view directly, +/// which would otherwise have black borders and move around when the headset moves because of +/// latency compensation. +/// ZEDManager creates a hidden camera with this script attached when in AR mode (see ZEDManager.CreateMirror()). /// public class ZEDMirror : MonoBehaviour { /// - /// Reference to the ZEDManager to get the texture overlay + /// The scene's ZEDManager component, for getting the texture overlay. /// public ZEDManager manager; /// - /// Reference to the texture overlay to get the render texture targeted + /// Reference to the ZEDRenderingPlane that renders the left eye, so we can get its target RenderTexture. /// private ZEDRenderingPlane textureOverlayLeft; void Start() { - UnityEngine.VR.VRSettings.showDeviceView = false; + UnityEngine.VR.VRSettings.showDeviceView = false; //Turn off default behavior. } private void Update() @@ -30,12 +34,11 @@ private void Update() } } - private void OnPostRender() + private void OnPostRender() //Called after the Camera component in this GameObject has rendered. { - if (textureOverlayLeft != null) { - Graphics.Blit(textureOverlayLeft.target, null as RenderTexture); + Graphics.Blit(textureOverlayLeft.target, null as RenderTexture); //Copy ZEDRenderingPlane's texture as the final image. } } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs index 37056280..be1b48af 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs @@ -6,11 +6,21 @@ using System.IO; /// -/// Manages the two finals cameras +/// In pass-through AR mode, handles the final output to the VR headset, positioning the final images +/// to make the pass-through effect natural and comfortable. Also moves/rotates the images to +/// compensate for the ZED image's latency using our Video Asynchronous Timewarp. +/// ZEDManager attaches this component to a second stereo rig called "ZEDRigDisplayer" that it +/// creates and hides in the editor at runtime; see ZEDManager.CreateZEDRigDisplayer() to see this process. +/// +/// The Timewarp effect is achieved by logging the pose of the headset each time it's available within the +/// wrapper. Then, when a ZED image is available, the wrapper looks up the headset's position using the timestamp +/// of the image, and moves the final viewing planes according to that position. In this way, the ZED's images +/// line up with real-life, even after a ~60ms latency. /// public class ZEDMixedRealityPlugin : MonoBehaviour { - const string nameDll = "sl_unitywrapper"; + #region DLL Calls + const string nameDll = "sl_unitywrapper"; [DllImport(nameDll, EntryPoint = "dllz_compute_size_plane_with_gamma")] private static extern System.IntPtr dllz_compute_size_plane_with_gamma(sl.Resolution resolution, float perceptionDistance, float eyeToZedDistance, float planeDistance, float HMDFocal, float zedFocal); @@ -45,18 +55,23 @@ public class ZEDMixedRealityPlugin : MonoBehaviour [DllImport(nameDll, EntryPoint = "dllz_drift_corrector_set_calibration_const_offset_transform")] public static extern void dllz_drift_corrector_set_calibration_const_offset_transform(ref Pose pose); + #endregion - /// - /// Container for the latency corrector - /// - public struct KeyPose + /// + /// Container for storing historic pose information, used by the latency corrector. + /// + public struct KeyPose { public Quaternion Orientation; public Vector3 Translation; public ulong Timestamp; }; - + /// + /// Container for position and rotation. Used when timestamps are not needed or have already + /// been processed, such as setting the initial camera offset or updating the stereo rig's + /// transform from data pulled from the wrapper. + /// [StructLayout(LayoutKind.Sequential)] public struct Pose { @@ -70,6 +85,9 @@ public Pose(Vector3 t, Quaternion q) } } + /// + /// + /// [StructLayout(LayoutKind.Sequential)] public struct TrackingData { @@ -79,97 +97,124 @@ public struct TrackingData public int trackingState; } - /// - /// Final GameObject Left - /// + /// + /// Gameobject holding the left camera in the final ZEDRigDisplayer rig, which captures the final image sent to the left HMD screen. + /// + [Tooltip("")] public GameObject finalCameraLeft; - /// - /// Final GameObject right - /// - public GameObject finalCameraRight; - - /// - /// Intermediate camera left - /// - public GameObject ZEDEyeLeft; - /// - /// Inytermediate camera right - /// - public GameObject ZEDEyeRight; - - /// - /// Intermediate Left screen - /// - public ZEDRenderingPlane leftScreen; - /// - /// Intermediate right screen - /// - public ZEDRenderingPlane rightScreen; - - /// - /// Final quad left - /// - public Transform quadLeft; - /// - /// Final quad right - /// - public Transform quadRight; - - /// - /// Final camera left - /// - public Camera finalLeftEye; - /// - /// Final camera right - /// - public Camera finalRightEye; - - /// - /// Material from the final right plane - /// - public Material rightMaterial; - /// - /// Material from the final left plane - /// - public Material leftMaterial; - - /// - /// Offset between the final plane and the camera - /// - public Vector3 offset = new Vector3(0, 0, (float)sl.Constant.PLANE_DISTANCE); - - /// - /// Half baseilne offset to set betwwen the two intermediate cameras - /// - public Vector3 halfBaselineOffset; - - /// - /// Reference to the ZEDCamera instance - /// - public sl.ZEDCamera zedCamera; - - /// - /// Reference to the ZEDManager - /// - public ZEDManager manager; - - /// - /// Flag set to true when the target textures from the overlays are ready - /// - public bool ready = false; - - /// - /// Flag grab ready, used to collect pose the latest time possible - /// - public bool grabSucceeded = false; - - /// - /// Flag the ZED is ready - /// - public bool zedReady = false; - - /// - /// Flag is VRDevice is detected. Updated at every frame + /// + /// GameObject holding the right camera in the final ZEDRigDisplayer rig, which captures the final image sent to the right HMD screen. + /// + [Tooltip("")] + public GameObject finalCameraRight; + + /// + /// 'Intermediate' left camera GameObject, which is the one on the regular, always-visible ZED stereo rig (ZED_Rig_Stereo), + /// usually called 'Left_eye'. + /// + [Tooltip("'Intermediate' left camera GameObject, which is the one on the regular, always-visible ZED stereo rig (ZED_Rig_Stereo), " + + "usually called 'Left_eye'. ")] + public GameObject ZEDEyeLeft; + /// + /// 'Intermediate' right camera GameObject, which is the one on the regular, always-visible ZED stereo rig (ZED_Rig_Stereo), + /// usually called 'Right_eye'. + /// + [Tooltip("'Intermediate' right camera GameObject, which is the one on the regular, always-visible ZED stereo rig (ZED_Rig_Stereo)," + + "usually called 'Right_eye'. ")] + public GameObject ZEDEyeRight; + + /// + /// 'Intermediate' left screen/canvas object in the always-visible ZED stereo rig. + /// + [Tooltip("")] + public ZEDRenderingPlane leftScreen; + /// + /// 'Intermediate' right screen/canvas object in the always-visible ZED stereo rig. + /// + [Tooltip("")] + public ZEDRenderingPlane rightScreen; + + /// + /// Final left viewing plane/canvas object in the final ZEDRigDisplayer rig. Displays the image from the left + /// 'intermediate' camera (ZEDEyeLeft) and is offset for image comfort and moved each frame for the Timewarp effect. + /// + [Tooltip("")] + public Transform quadLeft; + /// + /// Final right viewing plane/canvas object in the final ZEDRigDisplayer rig. Displays the image from the right + /// 'intermediate' camera (ZEDEyeRight) and is offset for image comfort and moved each frame for the Timewarp effect. + /// + [Tooltip("")] + public Transform quadRight; + + /// + /// Camera object in 'finalCameraLeft', which captures the final image output to the headset's left screen. + /// + [Tooltip("")] + public Camera finalLeftEye; + /// + /// Camera object in 'finalCameraRight', which captures the final image output to the headset's right screen. + /// + [Tooltip("")] + public Camera finalRightEye; + + /// + /// Material from the final left plane. Usually a new instance of Mat_ZED_Unlit. + /// + [Tooltip("Material from the final left plane. Usually a new instance of Mat_ZED_Unlit. ")] + public Material leftMaterial; + + /// + /// Material from the final right plane. Usually a new instance of Mat_ZED_Unlit. + /// + [Tooltip("Material from the final right plane. Usually a new instance of Mat_ZED_Unlit. ")] + public Material rightMaterial; + + /// + /// Base, pre-Timewarp offset between each final plane and its corresponding camera. + /// + [Tooltip("Offset between each final plane and its corresponding camera.")] + public Vector3 offset = new Vector3(0, 0, (float)sl.Constant.PLANE_DISTANCE); + + /// + /// Distance to set each intermediate camera from the point between them. This is half of the post-calibration + /// distance between the ZED cameras, so X is usually very close to 0.0315m (63mm / 2). + /// + [Tooltip("")] + public Vector3 halfBaselineOffset; + + /// + /// Reference to the ZEDCamera instance, which communicates with the SDK. + /// + [Tooltip("Reference to the ZEDCamera instance, which communicates with the SDK.")] + public sl.ZEDCamera zedCamera; + + /// + /// Reference to the scene's ZEDManager instance, usually contained in ZED_Rig_Stereo. + /// + [Tooltip("Reference to the scene's ZEDManager instance, usually contained in ZED_Rig_Stereo.")] + public ZEDManager manager; + + /// + /// Flag set to true when the target textures from the ZEDRenderingPlane overlays are ready. + /// + [Tooltip("Flag set to true when the target textures from the ZEDRenderingPlane overlays are ready.")] + public bool ready = false; + + /// + /// Flag set to true when a grab is ready, used to collect a pose from the latest time possible. + /// + [Tooltip("Flag set to true when a grab is ready, used to collect a pose from the latest time possible.")] + public bool grabSucceeded = false; + + /// + /// Flag set to true when the ZED is ready (after ZEDManager.OnZEDReady is invoked). + /// + [Tooltip("Flag set to true when the ZED is ready (after ZEDManager.OnZEDReady is invoked).")] + public bool zedReady = false; + + /// + /// If a VR device is still detected. Updated each frame. Used to know if certain updates should still happen. /// private bool hasVRDevice = false; public bool HasVRDevice { @@ -177,42 +222,57 @@ public bool HasVRDevice { } /// - /// The latency pose. + /// The current latency pose - the pose the headset was at when the last ZED frame was captured (based on its timestamp). /// private Pose latencyPose; - /// - /// HMD / ZED calibration - /// - private Pose hmdtozedCalibration; + /// + /// The physical offset of the HMD to the ZED. Represents the offset from the approximate center of the user's + /// head to the ZED's left sensor. + /// + private Pose hmdtozedCalibration; + + /// + /// Public accessor for the physical offset of the HMD to the ZED. Represents the offset from the + /// approximate center of the user's head to the ZED's left sensor. + /// public Pose HmdToZEDCalibration { get { return hmdtozedCalibration; } } /// - /// Check if the latency correction is ready + /// Whether the latency correction is ready. /// private bool latencyCorrectionReady = false; /// - /// Contains the last position computed by the anti drift + /// Contains the last position computed by the anti-drift. /// public TrackingData trackingData = new TrackingData(); - [SerializeField] + /// + /// Filename of the saved HMD to ZED calibration file loaded into hmdtozedCalibration. + /// //If it doesn't exist, it's created with hard-coded values. + /// + [Tooltip("")] + [SerializeField] private string calibrationFile = "CalibrationZEDHMD.ini"; + /// + /// Path of the saved HMD to ZED calibration file loaded into hmdtozedCalibration. + /// By default, corresponds to C:/ProgramData/Stereolabs/mr. + /// private string calibrationFilePath = @"Stereolabs\mr"; - - private RenderTexture finalLeftTexture; - - - - /// - /// Events / Delegate Action (when ZED is ready) - /// - public delegate void OnHmdCalibrationChanged(); - public static event OnHmdCalibrationChanged OnHdmCalibChanged; + /// + /// Delegate for the OnHMDCalibChanged event. + /// + public delegate void OnHmdCalibrationChanged(); + /// + /// Event invoked if the calibration file that sets the physical ZED offset is changed at runtime. + /// Causes ZEDManger.CalibrationHasChanged() to get called, which re-initialized the ZED's position + /// with ZEDManager.AdjustZEDRigCameraPosition() at the next tracking update. + /// + public static event OnHmdCalibrationChanged OnHmdCalibChanged; @@ -223,12 +283,18 @@ public Pose HmdToZEDCalibration { #endif private void Awake() { - hasVRDevice = VRDevice.isPresent; + //Initialize the latency tracking only if a supported headset is detected. + //You can force it to work for unsupported headsets by implementing your own logic for calling + //dllz_latency_corrector_initialize. + hasVRDevice = VRDevice.isPresent; if (hasVRDevice) { - if (VRDevice.model.ToLower().Contains ("vive")) + if (VRDevice.model.ToLower().Contains ("vive")) //Vive or Vive Pro dllz_latency_corrector_initialize (0); - else if (VRDevice.model.ToLower().Contains ("oculus")) + else if (VRDevice.model.ToLower().Contains ("oculus")) //Oculus Rift dllz_latency_corrector_initialize (1); + else if (VRDevice.model.ToLower().Contains ("windows")) //Windows MR through SteamVR Only (Beta) + dllz_latency_corrector_initialize (1); + dllz_drift_corrector_initialize (); } @@ -239,10 +305,11 @@ private void Awake() #endif } - /// - /// Start this instance. - /// - void Start() + /// + /// Sets references not set in ZEDManager.CreateZEDRigDisplayer(), sets materials, + /// adjusts final plane scale, loads the ZED calibration offset and other misc. values. + /// + void Start() { hasVRDevice = VRDevice.isPresent; manager = transform.parent.GetComponent(); @@ -258,24 +325,24 @@ void Start() finalRightEye.SetReplacementShader(rightMaterial.shader, ""); float plane_dist = (float)sl.Constant.PLANE_DISTANCE; - scale(quadLeft.gameObject, finalLeftEye, new Vector2(1.78f*plane_dist, 1.0f*plane_dist)); - scale(quadRight.gameObject, finalRightEye, new Vector2(1.78f*plane_dist, 1.0f*plane_dist)); + scale(quadLeft.gameObject, new Vector2(1.78f*plane_dist, 1.0f*plane_dist)); + scale(quadRight.gameObject, new Vector2(1.78f*plane_dist, 1.0f*plane_dist)); zedReady = false; Camera.onPreRender += PreRender; - LoadHmdToZEDCalibration(); + LoadHmdToZEDCalibration(); } /// - /// Compute the size of the final planes + /// Computes the size of the final planes. /// - /// - /// - /// - /// - /// - /// + /// ZED's current resolution. Usually 1280x720. + /// Typically 1. + /// Distance from your eye to the camera. Estimated at 0.1m. + /// Distance to final quad (quadLeft or quadRight). Arbitrary but set by offset.z. + /// Focal length of the HMD, retrieved from the wrapper. + /// Focal length of the ZED, retrieved from the camera's rectified calibration parameters. /// public Vector2 ComputeSizePlaneWithGamma(sl.Resolution resolution, float perceptionDistance, float eyeToZedDistance, float planeDistance, float HMDFocal, float zedFocal) { @@ -291,9 +358,9 @@ public Vector2 ComputeSizePlaneWithGamma(sl.Resolution resolution, float percept } /// - /// Compute the focal + /// Compute the focal length of the HMD. /// - /// + /// Resolution of the headset's eye textures. /// public float ComputeFocal(sl.Resolution targetSize) { @@ -301,13 +368,18 @@ public float ComputeFocal(sl.Resolution targetSize) return focal_hmd; } + /// + /// Called once the ZED is finished initializing. Subscribed to ZEDManager.OnZEDReady in OnEnable. + /// Uses the newly-available ZED parameters to scale the final planes (quadLeft and quadRight) to appear + /// properly in the currently-connected headset. + /// void ZEDReady() { Vector2 scaleFromZED; halfBaselineOffset.x = zedCamera.Baseline / 2.0f; float perception_distance = 1.0f; - float zed2eye_distance = 0.1f; + float zed2eye_distance = 0.1f; //Estimating 10cm between your eye and physical location of the ZED Mini. hasVRDevice = VRDevice.isPresent; if (hasVRDevice) { @@ -315,17 +387,17 @@ void ZEDReady() scaleFromZED = ComputeSizePlaneWithGamma (new sl.Resolution ((uint)zedCamera.ImageWidth, (uint)zedCamera.ImageHeight), perception_distance, zed2eye_distance, offset.z, - ComputeFocal (new sl.Resolution ((uint)UnityEngine.VR.VRSettings.eyeTextureWidth, (uint)UnityEngine.VR.VRSettings.eyeTextureHeight)),//571.677612f, + ComputeFocal (new sl.Resolution ((uint)UnityEngine.VR.VRSettings.eyeTextureWidth, (uint)UnityEngine.VR.VRSettings.eyeTextureHeight)), parameters.leftCam.fx); - - scale (quadLeft.gameObject, finalLeftEye, scaleFromZED); - scale (quadRight.gameObject, finalRightEye, scaleFromZED); + + scale (quadLeft.gameObject, scaleFromZED); + scale (quadRight.gameObject, scaleFromZED); ready = false; } - // Only for vive... some image adjustment + // If using Vive, change ZED's settings to compensate for different screen. if (VRDevice.model.ToLower().Contains ("vive")) { zedCamera.SetCameraSettings (sl.CAMERA_SETTINGS.CONTRAST, 3); zedCamera.SetCameraSettings (sl.CAMERA_SETTINGS.SATURATION, 3); @@ -336,10 +408,10 @@ void ZEDReady() finalLeftEye.stereoTargetEye = StereoTargetEyeMask.Left; finalRightEye.stereoTargetEye = StereoTargetEyeMask.Right; - /// AR Passtrough is recommended in 1280x720 at 60, due to fov, fps, etc...; - /// Set Warning for user + /// AR Passtrough is recommended in 1280x720 at 60, due to FoV, FPS, etc. + /// If not set to this resolution, warn the user. if (zedCamera.ImageWidth != 1280 && zedCamera.ImageHeight != 720) - Debug.LogWarning ("[ZED AR Passthrough] This resolution is not compatible with proper AR passthrough experience"); + Debug.LogWarning ("[ZED AR Passthrough] This resolution is not ideal for a proper AR passthrough experience. Recommended resolution is 1280x720."); zedReady = true; @@ -363,7 +435,7 @@ void OnGrab() } /// - /// Collect positions used in the latency corrector + /// Collects the position of the HMD with a timestamp, to be looked up later to correct for latency. /// public void CollectPose() { @@ -375,36 +447,45 @@ public void CollectPose() k.Timestamp = sl.ZEDCamera.GetInstance().GetCurrentTimeStamp(); if (k.Timestamp >= 0) { - dllz_latency_corrector_add_key_pose(ref k.Translation, ref k.Orientation, k.Timestamp); + dllz_latency_corrector_add_key_pose(ref k.Translation, ref k.Orientation, k.Timestamp); //Poses are handled by the wrapper. } } } - /// - /// Returns a pose at a specific time - /// - /// - /// - public int LatencyCorrector(out Quaternion r, out Vector3 t, ulong cameraTimeStamp,bool useLatency) + /// + /// Returns a pose at a specific time. + /// + /// Rotation of the latency pose. + /// Translation/position of the latency pose. + /// Timestamp for looking up the pose. + /// Whether to use latency. + public int LatencyCorrector(out Quaternion r, out Vector3 t, ulong cameraTimeStamp, bool useLatency) { - return dllz_latency_corrector_get_transform(cameraTimeStamp,useLatency,out t, out r); + return dllz_latency_corrector_get_transform(cameraTimeStamp, useLatency, out t, out r); } - public void scale(GameObject screen, Camera cam, Vector2 s) + /// + /// Sets the GameObject's 3D local scale based on a 2D resolution (Z scale is unchanged). + /// Used for scaling quadLeft/quadRight. + /// + /// Target GameObject to scale. + /// 2D scale factor. + public void scale(GameObject screen, Vector2 s) { screen.transform.localScale = new Vector3(s.x, s.y, 1); } /// - /// Set the pose to the final planes with the latency corrector + /// Set the planes/canvases to the proper position after accounting for latency. /// public void UpdateRenderPlane() { - if (!ZEDManager.IsStereoRig) return; + if (!ZEDManager.IsStereoRig) return; //Make sure we're in pass-through AR mode. Quaternion r; r = latencyPose.rotation; + //Plane's distance from the final camera never changes, but it's rotated around it based on the latency pose. quadLeft.localRotation = r; quadLeft.localPosition = finalLeftEye.transform.localPosition + r * (offset); quadRight.localRotation = r; @@ -413,9 +494,10 @@ public void UpdateRenderPlane() } /// - /// Init the tracking with the HMD IMU + /// Initialize the ZED's tracking with the current HMD position and HMD-ZED calibration. + /// This causes the ZED's internal tracking to start where the HMD is, despite being initialized later than the HMD. /// - /// + /// Initial offset for the ZED's tracking. public Pose InitTrackingAR() { Transform tmpHMD = transform; @@ -432,7 +514,10 @@ public Pose InitTrackingAR() return new Pose(tmpHMD.position, tmpHMD.rotation); } - + /// + /// Sets latencyPose to the pose of the headset at a given timestamp and flags whether or not it's valid for use. + /// + /// Timestamp for looking up the pose. public void ExtractLatencyPose(ulong cameraTimeStamp) { Quaternion latency_rot; @@ -444,17 +529,30 @@ public void ExtractLatencyPose(ulong cameraTimeStamp) latencyCorrectionReady = false; } + /// + /// Returns the most recently retrieved latency pose. + /// + /// + /// Last retrieved latency pose. public Pose LatencyPose() { return latencyPose; } + /// + /// Gets the proper position of the ZED virtual camera, factoring in HMD offset, latency, and anti-drift. + /// Used by ZEDManager to set the pose of Camera_eyes in the 'intermediate' rig (ZED_Rig_Stereo). + /// + /// Current position as returned by the ZED's tracking. + /// Current rotation as returned by the ZED's tracking. + /// Final rotation. + /// Final translation/position. public void AdjustTrackingAR(Vector3 position, Quaternion orientation, out Quaternion r, out Vector3 t) { hasVRDevice = VRDevice.isPresent; - Pose hmdTransform = new Pose(InputTracking.GetLocalPosition(VRNode.Head), InputTracking.GetLocalRotation(VRNode.Head)); - trackingData.trackingState = (int)manager.ZEDTrackingState; + Pose hmdTransform = new Pose(InputTracking.GetLocalPosition(VRNode.Head), InputTracking.GetLocalRotation(VRNode.Head)); //Current HMD position + trackingData.trackingState = (int)manager.ZEDTrackingState; //Whether the ZED's tracking is currently valid (not off or unable to localize). trackingData.zedPathTransform = new Pose (position, orientation); if (zedReady && latencyCorrectionReady) { @@ -466,17 +564,23 @@ public void AdjustTrackingAR(Vector3 position, Quaternion orientation, out Quate t = trackingData.offsetZedWorldTransform.translation; } - + /// + /// Close related ZED processes when the application ends. + /// private void OnApplicationQuit() { dllz_latency_corrector_shutdown(); dllz_drift_corrector_shutdown(); } + /// + /// Collects poses for latency correction, and updates the position of the rendering plane. + /// Also assigns textures from 'intermediate' cameras to the final quads' materials if ready and not done yet. + /// Called from ZEDManager.LateUpdate() so that it happens each frame after other tracking processes have finished. + /// public void LateUpdateHmdRendering() { - - if (!ready) + if (!ready) //Make sure intermediate cameras are rendering to the quad's materials. { if (leftScreen.target != null && leftScreen.target.IsCreated()) { @@ -493,16 +597,18 @@ public void LateUpdateHmdRendering() } - if (hasVRDevice) + if (hasVRDevice) //Do nothing if we no longer have a HMD connected. { - CollectPose (); - UpdateRenderPlane(); + CollectPose (); //File the current HMD pose into the latency poses to reference later. + UpdateRenderPlane(); //Reposition the final quads based on the latency pose. } } /// - /// Update Before ZED is actually ready + /// Before the ZED is ready, lock the quads in front of the cameras as latency correction isn't available yet. + /// This allows us to see the loading messages (and other virtual objects if desired) while the ZED is still loading. + /// Called by Camera.OnPreRender anytime any camera renders. /// /// Cam. public void PreRender(Camera cam) @@ -522,10 +628,12 @@ public void PreRender(Camera cam) } - /// - /// Loads the hmd to ZED calibration. - /// - public void LoadHmdToZEDCalibration() + /// + /// Loads the HMD to ZED calibration file and applies it to the hmdtozedCalibration offset. + /// Note that the file it loads is created using hard-coded values + /// and the ZED plugin doesn't ever change it. See CreateDefaultCalibrationFile(). + /// + public void LoadHmdToZEDCalibration() { if (hasVRDevice) { /// Default calibration (may be changed) @@ -559,6 +667,11 @@ public void LoadHmdToZEDCalibration() } } + /// + /// Creates a FileSystemEventHandler to watch the HMD-ZED calibration file and update settings if + /// it changes during runtime. If it does, calls OnChanged to fix tracking. + /// + /// public void CreateFileWatcher(string folder) { // Create a new FileSystemWatcher and set its properties. @@ -578,25 +691,35 @@ the renaming of files or directories. */ watcher.EnableRaisingEvents = true; } - // Define the event handlers. + /// + /// Reloads ZED-HMD offset calibration file and resets calibration accordintly. + /// Also calls OnHmdCalibChanged() which ZEDManager uses to run additional reset logic. + /// + /// + /// private void OnChanged(object source, FileSystemEventArgs e) { if (hasVRDevice) { ParseCalibrationFile (calibrationFilePath); dllz_drift_corrector_set_calibration_transform (ref hmdtozedCalibration); - OnHdmCalibChanged (); + OnHmdCalibChanged (); } } + /// + /// Creates and saves a text file with the default ZED-HMD offset calibration parameters, to be loaded anytime this class runs in the future. + /// Values correspond to the distance from the center of the user's head to the ZED's left sensor. + /// + /// Path to save the file. private void CreateDefaultCalibrationFile(string path) { - //Default Calibration : DO NOT CHANGE + //Default Calibration: DO NOT CHANGE. hmdtozedCalibration.rotation = Quaternion.identity; hmdtozedCalibration.translation.x = -0.0315f; hmdtozedCalibration.translation.y = 0.0f; hmdtozedCalibration.translation.z = 0.115f; - //Write calibration file using default calibration + //Write calibration file using default calibration. using (System.IO.StreamWriter file = new System.IO.StreamWriter (path)) { string node = "[HMD]"; string tx = "tx=" + hmdtozedCalibration.translation.x.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Translation x"; @@ -618,10 +741,14 @@ private void CreateDefaultCalibrationFile(string path) file.Close (); } - - //Default calibration already filled } + /// + /// Reads the ZED-HMD offset calibration file, if it exists, and loads calibration values to be applied to the final cameras. + /// Values correspond to the distance from the center of the user's head to the ZED's left sensor. + /// + /// Path to save the file. + /// False if the file couldn't be loaded, whether empty, non-existant, etc. private bool ParseCalibrationFile(string path) { if (!System.IO.File.Exists(path)) return false; @@ -638,6 +765,7 @@ private bool ParseCalibrationFile(string path) if (lines.Length==0) return false; + //Default to these values (which are the same ones put in the calibration file by default). hmdtozedCalibration.rotation = Quaternion.identity; hmdtozedCalibration.translation.x = -0.0315f; hmdtozedCalibration.translation.y = 0.0f; @@ -684,15 +812,11 @@ private bool ParseCalibrationFile(string path) } - //Check wrong calibration + //Check if the calibration has values but they're all zeros. if (hmdtozedCalibration.translation.x == 0.0f && hmdtozedCalibration.translation.y == 0.0f && hmdtozedCalibration.translation.z == 0.0f) { CreateDefaultCalibrationFile (path); } return true; } - - - - } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs index a4cf8320..02d0c8d3 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs @@ -8,33 +8,89 @@ #endif /// -/// Contols the ZEDSpatialMapping and hides its implementation +/// Manages the ZED SDK's plane detection feature. +/// This allows you to check a point on the screen to see if it's part of a real-life plane, such as +/// a floor, wall, tabletop, etc. If it is, this component will create a GameObject representing that +/// plane with its proper world position and boundaries. +/// If this component exists in your scene, you can also click the screen to detect planes there. +/// By default it adds a MeshCollider, so that physics objects can interact with it properly, and a +/// MeshRenderer, so that it's visible. +/// Planes are rendered with ZEDPlaneRenderer, so they aren't occluded, thereby avoiding Z-fighting with the +/// surfaces they represent. /// [DisallowMultipleComponent] public class ZEDPlaneDetectionManager : MonoBehaviour -{ - private GameObject holder; //Object all planes are parented to, called [ZED Planes] in Hierarchy +{ + /// + /// GameObject all planes are parented to. Created at runtime, called '[ZED Planes]' in Hierarchy. + /// + private GameObject holder; + + /// + /// Reference to the scene's ZEDManager component. Usually in the ZED_Rig_Mono or ZED_Rig_Stereo GameObject. + /// private ZEDManager manager = null; - private Camera LeftCamera = null; - private sl.ZEDCamera zedCam; - private bool isReady; - public bool IsReady{ - get { return isReady; } - } + /// + /// Reference to the left camera in the ZED rig. + /// + private Camera LeftCamera = null; + + /// + /// Reference to the current instance of ZEDCamera, which links the Unity plugin with the ZED SDK. + /// + private sl.ZEDCamera zedCam; + /// + /// Whether OnReady() has been called and finished. (OnReady() is called when the ZED finishes initializing) + /// + public bool IsReady { get; private set; } + + /// + /// Whether a floor plane has been detected during runtime. + /// This won't happen unless DetectFloorPlane() is called. + /// private bool hasDetectedFloor = false; + /// + /// Public accessor for hasDetectedFloor, which is whether a floor plane has been detected during runtime. + /// public bool HasDetectedFloor { get { return hasDetectedFloor; } } - private GameObject floorPlaneGO; - private ZEDPlaneGameObject floorPlane = null; + /// + /// GameObject holding floorPlane, which representing the floor plane, if one has been detected. + /// + private GameObject floorPlaneGO; + + /// + /// ZEDPlaneGameObject representing the floor plane, if one has been detected. + /// This reference is used to clear the existing floor plane if a new one is detected. + /// + private ZEDPlaneGameObject floorPlane = null; + + /// + /// Returns the ZEDPlaneGameObject representing the floor, if the floor has been detected. + /// public ZEDPlaneGameObject getFloorPlane{ get { return floorPlane; } } + /// + /// How many hit planes have been detected. Used to assign the index of hitPlaneList + /// to the ZEDPlaneGameObject's themselves, and to name their GameObjects. + /// private int planeHitCount = 0; + + /// + /// All the hit planes that have been detected using DetectPlaneAtHit(). + /// public List hitPlaneList = null; + + /// + /// Returns a ZEDPlaneGameObject with the provided index in hitPlaneList. + /// + /// Index within hitPlaneList. + /// public ZEDPlaneGameObject getHitPlane(int i) { if (i < hitPlaneList.Count) @@ -43,26 +99,61 @@ public ZEDPlaneGameObject getHitPlane(int i) return null; } - private Vector3[] planeMeshVertices; //Buffer for vertex data from SDK - private int[] planeMeshTriangles; //Buffer for triangle data from SDK - + /// + /// Buffer for holding a new plane's vertex data from the SDK. + /// + private Vector3[] planeMeshVertices; + /// + /// Buffer for holding a new plane's triangle data from the SDK. + /// + private int[] planeMeshTriangles; + + /// + /// Whether we're displaying the planes using ZEDPlaneRenderer. Usually the same as isVisibleInGameOption. + /// Used by ZEDRenderingPlane to know if it shold draw the meshes in its OnRenderImage() method. + /// public static bool isDisplay = false; + /// + /// Whether to enable physics in all new planes. + /// public bool addPhysicsOption = true; + + /// + /// Whether the planes are drawn in Unity's Scene view. + /// public bool isVisibleInSceneOption = true; + + /// + /// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build. + /// public bool isVisibleInGameOption = true; + /// + /// Overrides the default wireframe material used to draw planes in the Scene and Game view. + /// Leave this setting to null to draw the default wireframes. + /// public Material overrideMaterial = null; //If null, shows wireframe. Otherwise, displays your custom material. - private ZEDPlaneRenderer[] meshRenderer = new ZEDPlaneRenderer[2]; - - - public float GetEstimatedPlayerHeight { + /// + /// References to the ZEDPlaneRenderer components that draw the planes for each camera. + /// [0] is for the left eye, [1] is for the right (if applicable). + /// + private ZEDPlaneRenderer[] meshRenderer = new ZEDPlaneRenderer[2]; + + /// + /// How high the player's head is from the floor. Filled in when DetectFloorPlane() is called. + /// + private float estimatedPlayerHeight = 0.0f; + /// + /// Public accessor for estimatedPlayerHeight, which is how high the player's head was when DetectFloorPlane() was last called. + /// + public float GetEstimatedPlayerHeight { get { return estimatedPlayerHeight; } } - private float estimatedPlayerHeight = 0.0f; + /// - /// Start this instance. + /// Assign references, create the holder gameobject, and other misc. initialization. /// private void Start() { @@ -72,7 +163,7 @@ private void Start() LeftCamera = manager.GetLeftCameraTransform().gameObject.GetComponent(); zedCam = sl.ZEDCamera.GetInstance (); - isReady = false; + IsReady = false; //Create a holder for all the planes holder = new GameObject(); @@ -94,35 +185,33 @@ private void Start() /// - /// Event When ZED is ready + /// Handles initialization that can't happen until the ZED is finished initializing. + /// Called from ZEDManager.OnZEDReady. /// void ZEDReady() { if (LeftCamera) { - isReady = true; + IsReady = true; isDisplay = isVisibleInGameOption; SetPlaneRenderer (); } } - - /// - /// Raises the enable event. - /// + /// + /// Subscribes ZEDReady() to ZEDManager.OnZEDReady. + /// public void OnEnable() { ZEDManager.OnZEDReady += ZEDReady; } - - - /// - /// Raises the disable event. - /// - public void OnDisable() + /// + /// Unubscribes ZEDReady() from ZEDManager.OnZEDReady if it's disabled. + /// + public void OnDisable() { - if (isReady) { + if (IsReady) { foreach (Transform child in holder.transform) { GameObject.Destroy (child.gameObject); } @@ -132,13 +221,12 @@ public void OnDisable() ZEDManager.OnZEDReady -= ZEDReady; } - /// - /// Set the plane renderer to the cameras. Is necessary to see the planes + /// Adds ZEDPlaneRenderer components to the AR camera objects. + /// This is necessary in order to render the planes as an overlay. /// public void SetPlaneRenderer() { - if (manager != null) { Transform left = manager.GetLeftCameraTransform(); @@ -165,6 +253,7 @@ public void SetPlaneRenderer() /// /// Transforms the plane mesh from Camera frame to local frame, where each vertex is relative to the plane's center. + /// Used because plane data from the ZED SDK is relative to the camera, not the world. /// /// Camera transform. /// Source vertices (in camera space). @@ -175,9 +264,8 @@ public void SetPlaneRenderer() /// Number of triangles. private void TransformCameraToLocalMesh(Transform camera, Vector3[] srcVertices, int[] srcTriangles, Vector3[] dstVertices, int[] dstTriangles,int numVertices, int numTriangles, Vector3 centerpos) { - //Since we are in Camera if (numVertices == 0 || numTriangles == 0) - return; + return; //Plane is empty. System.Array.Copy(srcVertices, dstVertices, numVertices ); System.Buffer.BlockCopy(srcTriangles, 0, dstTriangles, 0, numTriangles * sizeof(int)); @@ -189,17 +277,19 @@ private void TransformCameraToLocalMesh(Transform camera, Vector3[] srcVertices, } - /// - /// Detects the floor plane. Replaces the current floor plane, if there is one, unlike DetectPlaneAtHit. - /// - /// true, if floor plane was detected, false otherwise. - public bool DetectFloorPlane(bool auto) + /// + /// Detects the floor plane. Replaces the current floor plane, if there is one, unlike DetectPlaneAtHit(). + /// If a floor is detected, also assigns the user's height from the floor to estimatedPlayerHeight. + /// + /// true, if floor plane was detected, false otherwise. + public bool DetectFloorPlane(bool auto) { - if (!isReady) - return false; + if (!IsReady) + return false; //Do nothing if the ZED isn't finished initializing. ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData(); - if (zedCam.findFloorPlane (ref plane, out estimatedPlayerHeight, Quaternion.identity, Vector3.zero) == sl.ERROR_CODE.SUCCESS) { + if (zedCam.findFloorPlane (ref plane, out estimatedPlayerHeight, Quaternion.identity, Vector3.zero) == sl.ERROR_CODE.SUCCESS) //We found a plane. + { int numVertices, numTriangles = 0; zedCam.convertFloorPlaneToMesh (planeMeshVertices, planeMeshTriangles, out numVertices, out numTriangles); if (numVertices > 0 && numTriangles > 0) { @@ -209,26 +299,29 @@ public bool DetectFloorPlane(bool auto) hasDetectedFloor = true; - if(!floorPlaneGO) + if(!floorPlaneGO) //Make the GameObject. { floorPlaneGO = new GameObject("Floor Plane"); floorPlaneGO.transform.SetParent(holder.transform); } - //Move the gameobject to the center of the plane. Note that the plane data's center is relative to the camera. + //Move the GameObject to the center of the plane. Note that the plane data's center is relative to the camera. floorPlaneGO.transform.position = LeftCamera.transform.position; //Add the camera's world position floorPlaneGO.transform.position += LeftCamera.transform.rotation * plane.PlaneCenter; //Add the center of the plane - if (!floorPlane) + if (!floorPlane) //Add a new ZEDPlaneGameObject to the floor plane if it doesn't already exist. { floorPlane = floorPlaneGO.AddComponent(); } - if (!floorPlane.IsCreated) { + if (!floorPlane.IsCreated) //Call ZEDPlaneGameObject.Create() on the floor ZEDPlaneGameObject if it hasn't yet been run. + { if(overrideMaterial != null) floorPlane.Create(plane, worldPlaneVertices, worldPlaneTriangles, 0, overrideMaterial); else floorPlane.Create (plane, worldPlaneVertices, worldPlaneTriangles, 0); floorPlane.SetPhysics (addPhysicsOption); - } else { + } + else //Update the ZEDPlaneGameObject with the new plane's data. + { floorPlane.UpdateFloorPlane (!auto,plane, worldPlaneVertices, worldPlaneTriangles, overrideMaterial); floorPlane.SetPhysics (addPhysicsOption); @@ -245,25 +338,26 @@ public bool DetectFloorPlane(bool auto) /// Detects the plane around screen-space coordinates specified. /// /// true, if plane at hit was detected, false otherwise. - /// position of the pixel in screen space (2D) + /// Position of the pixel in screen space (2D). public bool DetectPlaneAtHit(Vector2 screenPos) { - if (!isReady) - return false; + if (!IsReady) + return false; //Do nothing if the ZED isn't finished initializing. - ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData(); - if (zedCam.findPlaneAtHit(ref plane,screenPos) == sl.ERROR_CODE.SUCCESS) { + ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData(); + if (zedCam.findPlaneAtHit(ref plane,screenPos) == sl.ERROR_CODE.SUCCESS) //We found a plane. + { int numVertices, numTriangles = 0; zedCam.convertHitPlaneToMesh (planeMeshVertices, planeMeshTriangles, out numVertices, out numTriangles); if (numVertices > 0 && numTriangles > 0) { - GameObject newhitGO = new GameObject(); //TODO: Move to proper location. (Need to rework how the mesh works first, though) + GameObject newhitGO = new GameObject(); //Make a new GameObject to hold the new plane. newhitGO.transform.SetParent(holder.transform); Vector3[] worldPlaneVertices = new Vector3[numVertices]; int[] worldPlaneTriangles = new int[numTriangles]; TransformCameraToLocalMesh (LeftCamera.transform, planeMeshVertices, planeMeshTriangles, worldPlaneVertices, worldPlaneTriangles, numVertices, numTriangles, plane.PlaneCenter); - //Move the gameobject to the center of the plane. Note that the plane data's center is relative to the camera. + //Move the GameObject to the center of the plane. Note that the plane data's center is relative to the camera. newhitGO.transform.position = LeftCamera.transform.position; //Add the camera's world position newhitGO.transform.position += LeftCamera.transform.rotation * plane.PlaneCenter; //Add the center of the plane @@ -285,10 +379,10 @@ public bool DetectPlaneAtHit(Vector2 screenPos) } - /// - /// Update this instance. - /// - void Update() + /// + /// Check if the screen was clicked. If so, check for a plane where the click happened using DetectPlaneAtHit(). + /// + void Update() { if (Input.GetMouseButtonDown(0)) { Vector2 ScreenPosition = Input.mousePosition; @@ -297,15 +391,18 @@ void Update() } /// - /// Switchs the display. Set the static variable for rendering + /// Switches the IsDisplay setting, used to know if planes should be rendered. /// public void SwitchDisplay() { - if (isReady) + if (IsReady) isDisplay = isVisibleInGameOption; } #if UNITY_EDITOR + /// + /// Called when the Inspector is visible or changes. Updates plane physics and visibility settings. + /// void OnValidate() { if (floorPlane != null && floorPlane.IsCreated) { @@ -328,16 +425,35 @@ void OnValidate() #if UNITY_EDITOR +/// +/// Custom Inspector editor for ZEDPlaneDetectionManager. +/// Adds a button to detect the floor, and causes planes to get updated instantly when their visibility settings change. +/// [CustomEditor(typeof(ZEDPlaneDetectionManager ))] public class ZEDPlaneDetectionEditor : Editor { + /// + /// The ZEDPlaneDetectionManager component that this editor is displaying. + /// private ZEDPlaneDetectionManager planeDetector; - // private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) }; + // private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) }; - private SerializedProperty addPhysicsOption; + /// + /// Serializable version of ZEDPlaneDetectionManager's addPhysicsOption property. + /// + private SerializedProperty addPhysicsOption; + /// + /// Serializable version of ZEDPlaneDetectionManager's isVisibleInSceneOption property. + /// private SerializedProperty isVisibleInSceneOption; + /// + /// Serializable version of ZEDPlaneDetectionManager's isVisibleInGameOption property. + /// private SerializedProperty isVisibleInGameOption; + /// + /// Serializable version of ZEDPlaneDetectionManager's overrideMaterialOption property. + /// private SerializedProperty overrideMaterialOption; @@ -348,6 +464,7 @@ private ZEDPlaneDetectionManager Target public void OnEnable() { + //Assign the serialized properties to their appropriate properties. planeDetector = (ZEDPlaneDetectionManager)target; addPhysicsOption = serializedObject.FindProperty("addPhysicsOption"); isVisibleInSceneOption = serializedObject.FindProperty("isVisibleInSceneOption"); @@ -355,8 +472,6 @@ public void OnEnable() overrideMaterialOption = serializedObject.FindProperty("overrideMaterial"); } - - public override void OnInspectorGUI() { bool cameraIsReady = sl.ZEDCamera.GetInstance().IsCameraReady; @@ -372,8 +487,11 @@ public override void OnInspectorGUI() GUI.enabled = cameraIsReady; EditorGUILayout.BeginHorizontal(); - GUILayout.Label("Single-shot Floor Detection"); GUILayout.Space(20); - if (GUILayout.Button("Detect")) + GUIContent floordetectionlabel = new GUIContent("Single-shot Floor Detection", "Attempt to detect a floor plane in the current view."); + GUILayout.Label(floordetectionlabel); GUILayout.Space(20); + + GUIContent floordetectbuttonlabel = new GUIContent("Detect", "Attempt to detect a floor plane in the current view."); + if (GUILayout.Button(floordetectbuttonlabel)) { if (planeDetector.IsReady) planeDetector.DetectFloorPlane(false); @@ -387,8 +505,11 @@ public override void OnInspectorGUI() GUILayout.Label("Visualization", EditorStyles.boldLabel); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); - isVisibleInSceneOption.boolValue = EditorGUILayout.Toggle("Visible in Scene", isVisibleInSceneOption.boolValue); - isVisibleInGameOption.boolValue = EditorGUILayout.Toggle("Visible in Game", isVisibleInGameOption.boolValue && isVisibleInSceneOption.boolValue); + + GUIContent visiblescenelabel = new GUIContent("Visible in Scene", "Whether the planes are drawn in Unity's Scene view."); + GUIContent visiblegamelabel = new GUIContent("Visible in Game", "Whether the planes are drawn in Unity's Scene view."); + isVisibleInSceneOption.boolValue = EditorGUILayout.Toggle(visiblescenelabel, isVisibleInSceneOption.boolValue); + isVisibleInGameOption.boolValue = EditorGUILayout.Toggle(visiblegamelabel, isVisibleInGameOption.boolValue && isVisibleInSceneOption.boolValue); GUIContent overridematlabel = new GUIContent("Override Material: ", "Material applied to all planes if visible. If left empty, default materials will be applied depending on the plane type."); planeDetector.overrideMaterial = (Material)EditorGUILayout.ObjectField(overridematlabel, planeDetector.overrideMaterial, typeof(Material), false); @@ -401,11 +522,12 @@ public override void OnInspectorGUI() GUILayout.Label("Physics", EditorStyles.boldLabel); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); - addPhysicsOption.boolValue = EditorGUILayout.Toggle("Add Collider", addPhysicsOption.boolValue); + GUIContent physicslabel = new GUIContent("Add Collider", "Whether the planes can be collided with using physics."); + addPhysicsOption.boolValue = EditorGUILayout.Toggle(physicslabel, addPhysicsOption.boolValue); - serializedObject.ApplyModifiedProperties(); + serializedObject.ApplyModifiedProperties(); //Applies all changes to serializedproperties to the actual properties they're connected to. if (!cameraIsReady) Repaint(); diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs index 29cc6257..4884d42a 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs @@ -6,51 +6,111 @@ using System.Runtime.InteropServices; /// -/// Process the mesh taken from the ZED +/// Represents an individual plane that was detected by ZEDPlaneDetectionManager. +/// When created, it converts plane data from the ZED SDK into a mesh with proper world position/rotation. +/// This is necessary as the ZED SDK provides plane data relative to the camera. +/// It's also used to enable/disable collisions and visibility. /// public class ZEDPlaneGameObject : MonoBehaviour { - /// - /// Plane Type (horizontal, vertical, unknown) + /// Type of the plane, determined by its orientation and whether detected by ZEDPlaneDetectionManager's + /// DetectFloorPlane() or DetectPlaneAtHit(). /// public enum PLANE_TYPE { + /// + /// Floor plane of a scene. Retrieved by ZEDPlaneDetectionManager.DetectFloorPlane(). + /// FLOOR, + /// + /// Horizontal plane, such as a tabletop, floor, etc. Detected with DetectPlaneAtHit() using screen-space coordinates. + /// HIT_HORIZONTAL, + /// + /// Vertical plane, such as a wall. Detected with DetectPlaneAtHit() using screen-space coordinates. + /// HIT_VERTICAL, + /// + /// Plane at an angle neither parallel nor perpendicular to the floor. Detected with DetectPlaneAtHit() using screen-space coordinates. + /// HIT_UNKNOWN }; /// - /// Structure that defines a plane + /// Structure that defines a new plane, holding information directly from the ZED SDK. + /// Data within is relative to the camera; use ZEDPlaneGameObject's public fields for world-space values. /// [StructLayout(LayoutKind.Sequential)] public struct PlaneData { + /// + /// Error code returned by the ZED SDK when the plane detection was attempted. + /// public sl.ERROR_CODE ErrorCode; + /// + /// Type of the plane (floor, hit_vertical, etc.) + /// public ZEDPlaneGameObject.PLANE_TYPE Type; + /// + /// Normalized vector of the direction the plane is facing. + /// public Vector3 PlaneNormal; + /// + /// Camera-space position of the center of the plane. + /// public Vector3 PlaneCenter; + /// + /// Camera-space position of the center of the plane. + /// public Vector3 PlaneTransformPosition; + /// + /// Camera-space rotation/orientation of the plane. + /// public Quaternion PlaneTransformOrientation; + /// + /// The mathematical Vector4 equation of the plane. + /// public Vector4 PlaneEquation; + /// + /// How wide and long/tall the plane is in meters. + /// public Vector2 Extents; + /// + /// How many points make up the plane's bounds, eg. the array length of Bounds. + /// public int BoundsSize; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + ///Positions of the points that make up the edges of the plane's mesh. public Vector3[] Bounds; //max 256 points } + /// + /// Copy of the PlaneData structure provided by the ZED SDK when the plane was first detected. + /// Position, orientation, normal and equation are relative to the ZED camera at time of detection, not the world. + /// public ZEDPlaneGameObject.PlaneData planeData; + /// + /// Whether the plane has had Create() called yet to build its mesh. + /// private bool isCreated = false; + /// + /// Public accessor for isCreated, which is hether the plane has had Create() called yet to build its mesh. + /// public bool IsCreated { get { return isCreated; } } + /// + /// Normalized vector representing the direction the plane is facing in world space. + /// public Vector3 worldNormal { get; private set; } + /// + /// Position of the plane's center in world space. + /// public Vector3 worldCenter { get @@ -59,14 +119,21 @@ public Vector3 worldCenter } } + /// + /// Creates a mesh from given plane data and assigns it to new MeshFilter, MeshRenderer and MeshCollider components. + /// + /// + /// + /// + /// private void SetComponents(PlaneData plane, Vector3[] vertices, int[] triangles, Material rendermaterial) { - //Create the mesh filter to render the mesh + //Create the MeshFilter to render the mesh MeshFilter mf = gameObject.GetComponent(); if (mf == null) mf = gameObject.AddComponent(); - //Eliminate superfluous verts + //Eliminate superfluous vertices. int highestvertindex = 0; for (int i = 0; i < triangles.Length; i++) { @@ -75,7 +142,7 @@ private void SetComponents(PlaneData plane, Vector3[] vertices, int[] triangles, System.Array.Resize(ref vertices, highestvertindex + 1); - //Calculate the UVs for the vertices based on world space so they line up with other planes + //Calculate the UVs for the vertices based on world space, so they line up with other planes. Vector2[] uvs = new Vector2[vertices.Length]; Quaternion rotatetobackward = Quaternion.FromToRotation(worldNormal, Vector3.back); for (int i = 0; i < vertices.Length; i++) @@ -84,6 +151,7 @@ private void SetComponents(PlaneData plane, Vector3[] vertices, int[] triangles, uvs[i] = new Vector2(upwardcoords.x, upwardcoords.y); } + //Apply the new data to the MeshFilter's mesh and update it. mf.mesh.Clear(); mf.mesh.vertices = vertices; mf.mesh.triangles = triangles; @@ -91,19 +159,20 @@ private void SetComponents(PlaneData plane, Vector3[] vertices, int[] triangles, mf.mesh.RecalculateNormals(); mf.mesh.RecalculateBounds(); - // Get the mesh renderer and set properties + //Get the MeshRenderer and set properties. MeshRenderer mr = gameObject.GetComponent(); if (mr == null) mr = gameObject.AddComponent(); mr.material = rendermaterial; + //Turn off light and shadow effects, as the planes are meant to highlight a real-world object, not be a distinct object. mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; mr.receiveShadows = false; mr.enabled = true; mr.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; mr.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; - // Get the mesh collider and set properties + //Get the MeshCollider and apply the new mesh to it. MeshCollider mc = gameObject.GetComponent(); if (mc == null) mc = gameObject.AddComponent(); @@ -114,26 +183,30 @@ private void SetComponents(PlaneData plane, Vector3[] vertices, int[] triangles, } /// - /// Create the plane as a gameobject and fills the internal structure planeData for future access + /// Create the plane as a GameObject, and fills the internal PlaneData structure for future access. /// - /// Holder. - /// PlaneData fills by findXXXPlane(). - /// Vertices of the mesh - /// Triangles of the mesh + /// Scene's holder object to which all planes are parented. + /// PlaneData filled by the ZED SDK. + /// Vertices of the mesh. + /// Triangles of the mesh. + /// If a hit plane, the total number of hit planes detected prior to and including this one. public void Create(PlaneData plane, Vector3[] vertices, int[] triangles, int opt_count) { Create(plane, vertices, triangles, opt_count, GetDefaultMaterial(plane.Type)); } /// - /// Create the plane as a gameobject and fills the internal structure planeData for future access + /// Create the plane as a GameObject with a custom material, and fills the internal PlaneData structure for future access. /// - /// Holder. - /// PlaneData fills by findXXXPlane(). - /// Vertices of the mesh - /// Triangles of the mesh + /// Scene's holder object to which all planes are parented. + /// PlaneData filled by the ZED SDK. + /// Vertices of the mesh. + /// Triangles of the mesh. + /// If a hit plane, the total number of hit planes detected prior to and including this one. + /// Material to replace the default wireframe plane material. public void Create(PlaneData plane, Vector3[] vertices, int[] triangles, int opt_count, Material rendermaterial) { + //Copy the supplied PlaneData into this component's own PlaneData, for accessing later. planeData.ErrorCode = plane.ErrorCode; planeData.Type = plane.Type; planeData.PlaneNormal = plane.PlaneNormal; @@ -146,15 +219,14 @@ public void Create(PlaneData plane, Vector3[] vertices, int[] triangles, int opt planeData.Bounds = new Vector3[plane.BoundsSize]; System.Array.Copy (plane.Bounds, planeData.Bounds, plane.BoundsSize); - - //Set normal in world space + //Calculate the world space normal. Camera leftCamera = ZEDManager.Instance.GetLeftCameraTransform().gameObject.GetComponent(); worldNormal = leftCamera.transform.TransformDirection(planeData.PlaneNormal); - ///Create the MeshCollider + //Create the MeshCollider. gameObject.AddComponent().sharedMesh = null; - if (plane.Type != PLANE_TYPE.FLOOR) + if (plane.Type != PLANE_TYPE.FLOOR) //Give it a name. gameObject.name = "Hit Plane " + opt_count; else gameObject.name = "Floor Plane"; @@ -169,22 +241,18 @@ public void Create(PlaneData plane, Vector3[] vertices, int[] triangles, int opt /// - /// Updates the floor plane using "force" mode + /// Updates the floor plane with new plane data, if /// /// true, if floor plane was updated, false otherwise. /// If set to true force the update. Is set to false, update only if new plane/mesh is bigger or contains the old one - /// Plane. - /// Vertices. - /// Triangles. + /// PlaneData returned from the ZED SDK. + /// Vertices of the new plane mesh. + /// Triangles of the new plane mesh. public bool UpdateFloorPlane(bool force, ZEDPlaneGameObject.PlaneData plane, Vector3[] vertices, int[] triangles, Material rendermaterial = null) { - //Needs to be created - if (gameObject == null) - return false; - bool need_update = false; - //Check mesh - if (!force) + + if (!force) //Not force mode. Check if the new mesh contains or is larger than the old one. { if (!gameObject.GetComponent().isVisible) need_update = true; @@ -205,7 +273,7 @@ public bool UpdateFloorPlane(bool force, ZEDPlaneGameObject.PlaneData plane, Vec } } - else + else //Force mode. Update the mesh regardless of the existing mesh. need_update = true; if (need_update) @@ -232,9 +300,9 @@ public bool UpdateFloorPlane(bool force, ZEDPlaneGameObject.PlaneData plane, Vec /// - /// Enable the Mesh collider of the game object + /// Enable/disable the MeshCollider component to turn on/off collisions. /// - /// If set to true c. + /// If set to true, collisions will be enabled. public void SetPhysics(bool c) { MeshCollider mc = gameObject.GetComponent(); @@ -243,7 +311,7 @@ public void SetPhysics(bool c) } /// - /// Sets the Plane visible on the Scene + /// Enable/disable the MeshRenderer component to turn on/off visibility. /// /// If set to true c. public void SetVisible(bool c) @@ -254,7 +322,7 @@ public void SetVisible(bool c) } /// - /// Gets the size of the bounding rect that fits the plane + /// Gets the size of the bounding rect that fits the plane (aka 'extents'). /// /// The scale. public Vector2 GetScale() @@ -262,7 +330,10 @@ public Vector2 GetScale() return planeData.Extents; } - + /// + /// Returns the bounds of the plane from the MeshFilter. + /// + /// public Bounds GetBounds() { MeshFilter mf = gameObject.GetComponent(); @@ -297,15 +368,6 @@ public float getMinimumDistanceToBoundaries(Vector3 worldPosition,out Vector3 mi return minimal_distance; } - /// - /// Destroy this instance. - /// - public void Destroy() - { - if (gameObject != null) - GameObject.Destroy(gameObject); - - } /// /// Determines whether this floor plane is visible by any camera. @@ -316,6 +378,12 @@ public bool IsFloorPlaneVisible() return gameObject.GetComponent().isVisible; } + /// + /// Loads the default material for a plane, given its plane type. + /// Blue wireframe for floor planes and pink wireframe for hit planes. + /// + /// Type of plane based on its orientation and if it's the scene's floor plane. + /// private Material GetDefaultMaterial(PLANE_TYPE type) { //Find the default material for the plane type @@ -334,7 +402,7 @@ private Material GetDefaultMaterial(PLANE_TYPE type) break; default: - //Unknown planes are white + //Misc. planes are white defaultmaterial.SetColor("_WireColor", new Color(1, 1, 1, 174.0f / 255.0f)); break; } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneRenderer.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneRenderer.cs index a3f73a61..36a897a5 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneRenderer.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneRenderer.cs @@ -4,54 +4,58 @@ using UnityEngine; /// -/// Renders the Plane generated by the ZED in a second camera to get the alpha mesh style with no performance loss -/// This scripts is very similar to the ZED spatial mapping manager +/// Renders planes detected by ZEDPlaneDetectionManager in a second, hidden camera created at runtume. +/// This gets the alpha mesh style with no performance loss. +/// This script is very similar to how ZEDMeshRenderer works for spatial mapping. /// public class ZEDPlaneRenderer : MonoBehaviour { - /// - /// Refernce to the camera created + /// Reference to the hidden camera we create at runtime. /// private Camera cam; /// - /// Target texture of the rendering done by the the camera + /// Target texture of the rendering done by the new camera. /// private RenderTexture planeTex; /// - /// Checks if the spatial mapping has started + /// Checks if the ZED and this script have both finished initializing. /// private bool isReady = false; /// - /// Shaders used to render with - /// - - /// - /// Refernce to a textureOverlay + /// Reference to the ZEDRenderingPlane component of the camera we copy. /// - private ZEDRenderingPlane textureOverlay; + private ZEDRenderingPlane renderingPlane; - //Creates a camera to render only the Mesh + /// + /// Creates the duplicate camera that renders only the planes. + /// Rendering targets a RenderTexture that ZEDRenderingPlane will blend in at OnRenderImage(). + /// This gets called by ZEDManager.OnZEDReady when the ZED is finished initializing. + /// void ZEDReady() { + //Create the new GameObject and camera as a child of the corresponding ZED rig camera. GameObject go = new GameObject("PlaneCamera"); go.transform.parent = transform; go.transform.localPosition = Vector3.zero; go.transform.localRotation = Quaternion.identity; go.transform.localScale = Vector3.one; cam = go.AddComponent(); - go.hideFlags = HideFlags.HideAndDontSave; + go.hideFlags = HideFlags.HideAndDontSave; //This hides the new camera from scene view. Comment this out to see it in the hierarchy. + + //Set the target texture to a new RenderTexture that will be passed to ZEDRenderingPlane for blending. if (sl.ZEDCamera.GetInstance().IsCameraReady) { planeTex = new RenderTexture(sl.ZEDCamera.GetInstance().ImageWidth, sl.ZEDCamera.GetInstance().ImageHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); planeTex.Create(); } + //Set the camera's parameters. cam.enabled = false; - cam.cullingMask = (1 << sl.ZEDCamera.TagOneObject); + cam.cullingMask = (1 << sl.ZEDCamera.TagOneObject); //Layer set aside for planes and spatial mapping meshes. cam.targetTexture = planeTex; cam.nearClipPlane = 0.1f; cam.farClipPlane = 100.0f; @@ -67,29 +71,37 @@ void ZEDReady() cam.allowMSAA = false; cam.allowHDR = false; #endif + cam.useOcclusionCulling = false; - textureOverlay = GetComponent(); - textureOverlay.SetTextureOverlayMapping(planeTex); + //Set the ZEDRenderingPlane blend texture to the one the new camera renders to. + renderingPlane = GetComponent(); + renderingPlane.SetTextureOverlayMapping(planeTex); isReady = true; } - + /// + /// Subscribes to ZEDManager.OnZEDReady. + /// private void OnEnable() { ZEDManager.OnZEDReady += ZEDReady; } + /// + /// Unsubscribes from ZEDManager.OnZEDReady. + /// private void OnDisable() { ZEDManager.OnZEDReady -= ZEDReady; } - - // Update is called once per frame + /// + /// Renders the plane each frame, before cameras normally update, so the RenderTexture is ready to be blended. + /// void Update() { if (isReady) @@ -100,6 +112,9 @@ void Update() } } + /// + /// Releases the target RenderTexture when the application quits. + /// private void OnApplicationQuit() { if (planeTex != null && planeTex.IsCreated()) diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs index cfc208a4..d58797f3 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs @@ -4,61 +4,71 @@ using UnityEngine; /// -/// Renders the Mesh generated by the ZED in a second camera to get the wireframe style with no performance loss +/// Renders the mesh generated by ZEDSpatialMappingManager in a second, hidden camera created at runtume. +/// This gets the wireframe style with no performance loss. +/// This script is very similar to how ZEDPlaneRenderer works for Plane Detection. /// public class ZEDMeshRenderer : MonoBehaviour { /// - /// Refernce to the camera created + /// Reference to the hidden camera we create at runtime. /// private Camera cam; /// - /// Target texture of the rendering done by the the camera + /// Target texture of the rendering done by the new camera. /// - private RenderTexture planeTex; + private RenderTexture meshTex; /// - /// Checks if the spatial mapping has started + /// Checks if the spatial mapping has started. /// private bool hasStarted = false; /// - /// Checks if the mesh requested is textured, descativate the wireframe + /// Checks if the mesh requested is textured. If so, deativate the wireframe. /// [HideInInspector] static public bool isTextured = false; /// - /// Shaders used to render with + /// Shader used to render the wireframe. Normally Mat_ZED_Wireframe_Video_Overlay. /// private Shader shaderWireframe; /// - /// Refernce to a textureOverlay + /// Reference to the ZEDRenderingPlane component of the camera we copy. /// - private ZEDRenderingPlane textureOverlay; + private ZEDRenderingPlane renderingPlane; - //Creates a camera to render only the Mesh + /// + /// Creates the duplicate camera that renders only the scanned mesh. + /// Rendering targets a RenderTexture that ZEDRenderingPlane will blend in at OnRenderImage(). + /// This gets called by ZEDManager.OnZEDReady when the ZED is finished initializing. + /// void ZEDReady() { + //Create the new GameObject and camera as a child of the corresponding ZED rig camera. GameObject go = new GameObject("MeshCamera"); go.transform.parent = transform; go.transform.localPosition = Vector3.zero; go.transform.localRotation = Quaternion.identity; go.transform.localScale = Vector3.one; cam = go.AddComponent(); - go.hideFlags = HideFlags.HideAndDontSave; - if (sl.ZEDCamera.GetInstance().IsCameraReady) + go.hideFlags = HideFlags.HideAndDontSave;//This hides the new camera from scene view. Comment this out to see it in the hierarchy. + + //Set the target texture to a new RenderTexture that will be passed to ZEDRenderingPlane for blending. + if (sl.ZEDCamera.GetInstance().IsCameraReady) { - planeTex = new RenderTexture(sl.ZEDCamera.GetInstance().ImageWidth, sl.ZEDCamera.GetInstance().ImageHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); - planeTex.Create(); + meshTex = new RenderTexture(sl.ZEDCamera.GetInstance().ImageWidth, sl.ZEDCamera.GetInstance().ImageHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); + meshTex.Create(); } + //Set the camera's parameters. cam.enabled = false; - cam.cullingMask = (1 << sl.ZEDCamera.TagOneObject); - cam.targetTexture = planeTex; + cam.cullingMask = (1 << sl.ZEDCamera.TagOneObject); //Layer set aside for planes and spatial mapping meshes. + cam.targetTexture = meshTex; cam.nearClipPlane = 0.1f; cam.farClipPlane = 500.0f; cam.fieldOfView = sl.ZEDCamera.GetInstance().GetFOV() * Mathf.Rad2Deg; @@ -77,38 +87,42 @@ void ZEDReady() shaderWireframe = (Resources.Load("Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay") as Material).shader; - textureOverlay = GetComponent(); - textureOverlay.SetTextureOverlayMapping(planeTex); + //Set the ZEDRenderingPlane blend texture to the one the new camera renders to. + renderingPlane = GetComponent(); + renderingPlane.SetTextureOverlayMapping(meshTex); } - - + /// + /// Subscribes to relevant events. + /// private void OnEnable() { ZEDSpatialMapping.OnMeshStarted += SpatialMappingStarted; - ZEDSpatialMapping.OnMeshReady += SpatialMappingOver; ZEDManager.OnZEDReady += ZEDReady; } + /// + /// Unsubscribes from relevant events. + /// private void OnDisable() { ZEDSpatialMapping.OnMeshStarted -= SpatialMappingStarted; - ZEDSpatialMapping.OnMeshReady -= SpatialMappingOver; ZEDManager.OnZEDReady -= ZEDReady; } - private void SpatialMappingOver() - { - } - + /// + /// Sets hasStarted to true. Called from ZEDSpatialMapping once it has started scanning. + /// void SpatialMappingStarted() { hasStarted = true; } - // Update is called once per frame + /// + /// Renders the plane each frame, before cameras normally update, so the RenderTexture is ready to be blended. + /// void Update() { if (ZEDSpatialMapping.display && hasStarted) @@ -121,11 +135,14 @@ void Update() } } + /// + /// Releases the target RenderTexture when the application quits. + /// private void OnApplicationQuit() { - if (planeTex != null && planeTex.IsCreated()) + if (meshTex != null && meshTex.IsCreated()) { - planeTex.Release(); + meshTex.Release(); } } } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs index cb216c34..fceaa61f 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs @@ -5,45 +5,46 @@ using System.Threading; /// -/// Process the mesh taken from the ZED +/// Processes the mesh taken from the ZED's Spatial Mapping feature so it can be used within Unity. +/// Handles the real-time updates as well as the final processing. +/// Note that ZEDSpatialMappingManager is more user-friendly/high-level, designed to hide the complexities of this class. /// public class ZEDSpatialMapping { - /// - /// Submesh created by the ZEDSpatialMapping + /// Submesh created by ZEDSpatialMapping. The scan is made of multiple chunks. /// public struct Chunk { /// - /// Contains the gameobject + /// Reference to the GameObject that holds the MeshFilter. /// public GameObject o; /// - /// Dynamic mesh, will change during the spatial mapping + /// Dynamic mesh data that will change throughout the spatial mapping. /// public ProceduralMesh proceduralMesh; /// - /// Final mesh, should be used at the end of the spatial mapping + /// Final mesh, assigned to once the spatial mapping is over and done processing. /// public Mesh mesh; } /// - /// Structure to contain a temporary buffer in change for triangles and vertices + /// Structure to contain a temporary buffer that holds triangles and vertices. /// public struct ProceduralMesh { /// - /// List of indices + /// List of vertex indexes that make up triangles. /// public int[] triangles; /// - /// List of vertices + /// List of vertices in the mesh. /// public Vector3[] vertices; /// - /// Interface mesh for Unity + /// MeshFilter of a GameObject that holds the chunk this ProceduralMesh represents. /// public MeshFilter mesh; }; @@ -51,114 +52,120 @@ public struct ProceduralMesh /// - /// List the spatial mapping depth resolution presets. + /// Spatial mapping depth resolution presets. /// public enum RESOLUTION { /// - /// Create a detail geometry, requires lots of memory. + /// Create detailed geometry. Requires lots of memory. /// HIGH, /// - /// Smalls variations in the geometry will disappear, useful for big object. + /// Small variations in the geometry will disappear. Useful for large objects. /// /// MEDIUM, /// - /// Keeps only huge variations of the geometry , useful outdoor. + /// Keeps only large variations of the geometry. Useful for outdoors. /// LOW } /// - /// List the spatial mapping depth range presets. + /// Spatial mapping depth range presets. /// public enum RANGE { /// - /// Only depth close to the camera will be used by the spatial mapping. + /// Geometry within 3.5 meters of the camera will be mapped. /// NEAR, /// - /// Medium depth range. + /// Geometry within 5 meters of the camera will be mapped. /// MEDIUM, /// - /// Takes into account objects that are far, useful outdoor. + /// Objects as far as 10 meters away are mapped. Useful for outdoors. /// FAR } - /// - /// Current instance of the ZED Camera + /// Current instance of the ZED Camera. /// private sl.ZEDCamera zedCamera; /// - /// Internal class used to help + /// Instance of an internal helper class for low-level mesh processing. /// - private ZEDSpatialMappingHelper zedSpatialMapping; - + private ZEDSpatialMappingHelper spatialMappingHelper; + /// + /// Amount of filtering to apply to the mesh. Higher values result in lower face counts/memory usage, but also lower precision. + /// public sl.FILTER filterParameters = sl.FILTER.MEDIUM; + #if UNITY_EDITOR + /// + /// Color of the wireframe mesh to be drawn in Unity's Scene window. + /// private Color colorMesh = new Color(0.35f, 0.65f, 0.95f); #endif /// - /// Offset for the triangles buffer + /// Offset for the triangles buffer, so that new triangles are copied into the dynamic mesh starting at the correct index. /// private int trianglesOffsetLastFrame; /// - /// Offset for the vertices buffer + /// Offset for the vertices buffer, so that new vertices are copied into the dynamic mesh starting at the correct index. /// private int verticesOffsetLastFrame; /// - /// Offset for the uvs buffer + /// Offset for the UVs buffer, so that new UV coordinates are copied into the dynamic mesh starting at the correct index. /// private int uvsOffsetLastFrame; /// - /// Index of the mesh during last frame + /// Index of the mesh that was updated last frame. /// private int indexLastFrame; /// - /// Flag if remains meshes to process (due to lack of time) + /// Flag set to true if there were meshes what weren't completely updated last frame due to lack of time. /// private bool remainMeshes = false; /// - /// Stop has been wanted by the user + /// The user has requested to stop spatial mapping. /// private bool stopWanted = false; /// - /// The mesh is in the state of filtering + /// Whether the mesh is in the filtering stage of processing. /// private bool isFiltering = false; /// - /// Flag checking if the filtering is over + /// Whether the filtering stage of the mesh's processing has started and finished. /// private bool isFilteringOver = false; /// - /// The update of the thread is over + /// Whether the update thread will stop running. /// private bool stopRunning = false; /// - /// Checks if the thread is running, and if the spatial mapping is running + /// Whether any part of spatial mapping is running. Set to true when scanning has started + /// and set to false after the scanned mesh has finished bring filtered, textured, etc. /// private bool running = false; /// - /// Flag to set a pause + /// Flag that causes spatial mapping to pause when true. Use SwitchPauseState() to change. /// private bool pause = false; /// - /// Returns the state of the pause + /// Returns true if spatial mapping has been paused. This can be set to true even if spatial mapping isn't running. /// public bool IsPaused { @@ -166,91 +173,113 @@ public bool IsPaused } /// - /// Checks if the display of the mesh is wanted + /// Whether scanned meshes are visible or not. /// public static bool display = false; /// - /// State of the scanning during it's init + /// State of the scanning during its initialization. Used to know if it has started successfully. /// private sl.ERROR_CODE scanningInitState; /// - /// Eevents called when a new mesh had been processed. Is called many times. + /// Delegate for the OnMeshUpdate event, which is called every time a new chunk/submesh is processed. /// public delegate void OnNewMesh(); + /// + /// Events called every time a new chunk/submesh has been processed. It's called many times during the scan. + /// public static event OnNewMesh OnMeshUpdate; /// - /// Event called at the end of the spatial mapping + /// Delegate for OnMeshReady, which is called when spatial mapping has finished. /// public delegate void OnSpatialMappingEnded(); + /// + /// Event called when spatial mapping has finished. + /// public static event OnSpatialMappingEnded OnMeshReady; /// - /// Event called when the spatial mapping has started + /// Delegate for OnMeshStarted, which is called when spatial mapping has started. /// public delegate void OnSpatialMappingStarted(); + /// + /// Event called when spatial mapping has started. + /// public static event OnSpatialMappingStarted OnMeshStarted; /// - /// Chunks holder + /// GameObject to which every chunk of the mesh is parented. Represents the scanned mesh in Unity's Hierarchy. /// private GameObject holder; /**** Threading Variables ****/ /// - /// The mesh has been updated, and needs to be processed + /// True if the mesh has been updated, and needs to be processed. /// private bool meshUpdated = false; /// - /// The thread is running + /// True if the mesh update thread is running. /// private bool updateThreadRunning = false; + /// + /// Public accessor for whether the mesh update thread is running. + /// public bool IsUpdateThreadRunning { get { return updateThreadRunning; } } /// - /// The spatial mapping should start + /// True if the user has requested that spatial mapping start. /// private bool spatialMappingRequested = false; + /// - /// Needs an update of a texture + /// True if the real-world texture needs to be updated. + /// This only happens after scanning is finished and if Texturing (isTextured) is enabled. /// private bool updateTexture = false; /// - /// Thetexture had been udpated + /// True if the real-world texture has been updated. /// private bool updatedTexture = false; /// - /// Thread retrieving the size of the meshes + /// Thread that retrieves the size of the submeshes. /// private Thread scanningThread; /// - /// Thread to filter + /// Thread that filters the mesh once scanning has finished. /// private Thread filterThread; + /// + /// Mutex for threaded spatial mapping. + /// private object lockScanning = new object(); /// - /// Max time in ms during the process of the mesh can be done, if the time is over, the flag remainMeshes is set to true + /// Maximum time in milliseconds that can be spent processing retrieved meshes each frame. If time is exceeded, remaining meshes will be processed next frame. /// private const int MAX_TIME = 5; + + /// + /// True if the thread that updates the real-world texture is running. + /// private bool texturingRunning = false; /// - /// Gravity estimation, set after the spatial mapping + /// Gravity direction vector relative to ZEDManager's orientation. Estimated after spatial mapping is finished. + /// Note that this will always be empty if using the ZED Mini as gravity is determined from its IMU at start. /// public Vector3 gravityEstimation; /// - /// Is tetxuring is running + /// Public accessor for texturingRunning, which is whether the thread that updates the real-world texture is running. /// public bool IsTexturingRunning { @@ -260,57 +289,76 @@ public bool IsTexturingRunning } } /// - /// Are colliders wanted + /// If true, the script will add MeshColliders to all scanned chunks to allow physics collisions. /// private bool hasColliders = true; /// - /// Checks if the mesh is textured + /// True if texture from the real world should be applied to the mesh. If true, texture will be applied after scanning is finished. /// private bool isTextured = false; - // Use this for initialization + + /// + /// Flag to check if we have attached ZEDMeshRenderer components to the ZED rig camera objects. + /// This is done in Update() if it hasn't been done yet. + /// private bool setMeshRenderer = false; - private ZEDManager zedManager; + /// + /// References to the ZEDMeshRenderer components attached to the ZED rig camera objects. + /// [0] is the one attached to the left camera. [1] is the right camera, if it exists. + /// private ZEDMeshRenderer[] meshRenderer = new ZEDMeshRenderer[2]; /// - /// The meshes with their indices. This dictionnay is updated only when running the spatial Mapping. Prefer using SubMeshesList to get the complete list of meshes if spatial mapping is stopped + /// The scene's ZEDManager component, usually attached to the ZED rig GameObject (ZED_Rig_Mono or ZED_Rig_Stereo). + /// + private ZEDManager zedManager; + + /// + /// All chunks/submeshes with their indices. Only used while spatial mapping is running, as meshes are consolidated from + /// many small meshes into fewer, larger meshes when finished. See ChunkList for final submeshes. /// public Dictionary Chunks { - get { return zedSpatialMapping.chunks; } + get { return spatialMappingHelper.chunks; } } /// - /// List final of meshes + /// List of the final mesh chunks created after scanning is finished. This is not filled beforehand because we use + /// many small chunks during scanning, and consolidate them afterward. See Chunks for runtime submeshes. /// public List ChunkList = new List(); - + /// + /// Constructor. Spawns the holder GameObject to hold scanned chunks and the ZEDSpatialMappingHelper to handle low-level mesh processing. + /// + /// Transform of the scene's ZEDSpatialMappingManager. + /// Reference to the ZEDCamera instance. + /// The scene's ZEDManager component. public ZEDSpatialMapping(Transform transform, sl.ZEDCamera zedCamera, ZEDManager zedManager) { - zedSpatialMapping = new ZEDSpatialMappingHelper(Resources.Load("Materials/SpatialMapping/Mat_ZED_Texture") as Material, Resources.Load("Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe") as Material); + //Instantiate the low-level mesh processing helper. + spatialMappingHelper = new ZEDSpatialMappingHelper(Resources.Load("Materials/SpatialMapping/Mat_ZED_Texture") as Material, Resources.Load("Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe") as Material); + //Assign basic values. this.zedCamera = zedCamera; this.zedManager = zedManager; scanningInitState = sl.ERROR_CODE.FAILURE; + //Create the Holder object, to which all scanned chunks will be parented. holder = new GameObject(); holder.name = "[ZED Mesh Holder]"; - //holder.hideFlags = HideFlags.HideInInspector; holder.transform.position = Vector3.zero; holder.transform.rotation = Quaternion.identity; StaticBatchingUtility.Combine(holder); } - - /// - /// Starts the spatial mapping + /// Begins the spatial mapping process. This is called when you press the "Start Spatial Mapping" button in the Inspector. /// - /// - /// - /// + /// Resolution setting - how detailed the mesh should be at scan time. + /// Range setting - how close geometry must be to be scanned. + /// Whether to scan texture, or only the geometry. public void StartStatialMapping(RESOLUTION resolutionPreset, RANGE rangePreset, bool isTextured) { holder.transform.position = Vector3.zero; @@ -323,44 +371,50 @@ public void StartStatialMapping(RESOLUTION resolutionPreset, RANGE rangePreset, zedManager.gravityRotation = Quaternion.identity; + pause = false; //Make sure the scanning doesn't start paused because it was left paused at the last scan. + } /// - /// Enable the spatial mapping + /// Initializes flags used during scan, tells ZEDSpatialMappingHelper to activate the ZED SDK's scanning, and + /// starts the thread that updates the in-game chunks with data from the ZED SDK. /// - /// A preset resolution - /// A preset range - /// if true, images will be collected during the process + /// Resolution setting - how detailed the mesh should be at scan time. + /// Range setting - how close geometry must be to be scanned. + /// Whether to scan texture, or only the geometry. /// private sl.ERROR_CODE EnableSpatialMapping(RESOLUTION resolutionPreset, RANGE rangePreset, bool isTextured) { sl.ERROR_CODE error; this.isTextured = isTextured; - error = zedSpatialMapping.EnableSpatialMapping(ZEDSpatialMappingHelper.ConvertResolutionPreset(resolutionPreset), ZEDSpatialMappingHelper.ConvertRangePreset(rangePreset), isTextured); - ZEDMeshRenderer.isTextured = false; - stopWanted = false; + + //Tell the helper to start scanning. This call gets passed directly to the wrapper call in ZEDCamera. + error = spatialMappingHelper.EnableSpatialMapping(ZEDSpatialMappingHelper.ConvertResolutionPreset(resolutionPreset), ZEDSpatialMappingHelper.ConvertRangePreset(rangePreset), isTextured); + ZEDMeshRenderer.isTextured = false; //Set to false even if we want a textured mesh, as the texture isn't available until after the scan. + stopWanted = false; running = true; - if (error == sl.ERROR_CODE.SUCCESS) + if (error == sl.ERROR_CODE.SUCCESS) //If the scan was started successfully. { + //Set default flag settings. display = true; meshUpdated = false; spatialMappingRequested = false; updateTexture = false; updatedTexture = false; - // clear all prevous meshes + //Clear all previous meshes. ClearMeshes(); - //start the requesting meshes + //Request the first mesh update. Later, this will get called continuously after each update is applied. zedCamera.RequestMesh(); - //Launch the thread to retrieve the chunks and their sizes + //Launch the thread to retrieve the chunks and their sizes from the ZED SDK. scanningThread = new Thread(UpdateMesh); updateThreadRunning = true; if (OnMeshStarted != null) { - OnMeshStarted(); + OnMeshStarted(); //Invoke the event for other scripts, like ZEDMeshRenderer. } scanningThread.Start(); } @@ -368,17 +422,15 @@ private sl.ERROR_CODE EnableSpatialMapping(RESOLUTION resolutionPreset, RANGE ra } /// - /// Set the mesh renderer to the cameras. Is necessary to see the mesh + /// Attach a new ZEDMeshRenderer to the ZED rig cameras. This is necessary to see the mesh. /// public void SetMeshRenderer() { - if (!setMeshRenderer) + if (!setMeshRenderer) //Make sure we haven't do this yet. { - - if (zedManager != null) + if (zedManager != null) { - Transform left = zedManager.GetLeftCameraTransform(); - + Transform left = zedManager.GetLeftCameraTransform(); //Find the left camera. This exists in both ZED_Rig_Mono and ZED_Rig_Stereo. if (left != null) { meshRenderer[0] = left.gameObject.GetComponent(); @@ -388,7 +440,7 @@ public void SetMeshRenderer() } } - Transform right = zedManager.GetRightCameraTransform(); + Transform right = zedManager.GetRightCameraTransform(); //Find the right camera. This only exists in ZED_Rig_Stereo or a similar stereo rig. if (right != null) { meshRenderer[1] = right.gameObject.GetComponent(); @@ -403,11 +455,11 @@ public void SetMeshRenderer() } /// - /// Updates the current mesh and manages the start and stop states + /// Updates the current mesh, if scanning, and manages the start and stop states. /// public void Update() { - SetMeshRenderer(); + SetMeshRenderer(); //Make sure we have ZEDMeshRenderers on the cameras, so we can see the mesh. if (meshUpdated || remainMeshes) { @@ -422,7 +474,7 @@ public void Update() Stop(); } - //Disable the spatial mapping and rotate the parent of the ZEDManager to apply the gravity estimation + //If it's time to stop the scan, disable the spatial mapping and store the gravity estimation in ZEDManager. if (stopRunning && !isFiltering && isFilteringOver) { isFilteringOver = false; @@ -451,21 +503,20 @@ public void Update() /// - /// Get the mesh data from the ZED camera and store it for later update in unity mesh. + /// Gets the mesh data from the ZED SDK and stores it for later update in the Unity mesh. /// private void UpdateMesh() { - while (updateThreadRunning) + while (updateThreadRunning) { - //If all the index are not over - if (!remainMeshes) + if (!remainMeshes) //If we don't have leftover meshes to apply from the last update. { lock (lockScanning) { - if (meshUpdated == false && updateTexture) + if (meshUpdated == false && updateTexture) //If we need to update the texture, prioritize that. { - //Get the last size of mesh and get the texture Size - zedSpatialMapping.ApplyTexture(); + //Get the last size of the mesh and get the texture size. + spatialMappingHelper.ApplyTexture(); meshUpdated = true; updateTexture = false; updatedTexture = true; @@ -473,17 +524,17 @@ private void UpdateMesh() } else if (zedCamera.GetMeshRequestStatus() == sl.ERROR_CODE.SUCCESS && !pause && meshUpdated == false) { - zedSpatialMapping.UpdateMesh(); - zedSpatialMapping.RetrieveMesh(); + spatialMappingHelper.UpdateMesh(); //Tells the ZED SDK to update its internal mesh. + spatialMappingHelper.RetrieveMesh(); //Applies the ZED SDK's internal mesh to values inside spatialMappingHelper. meshUpdated = true; } } - //Time to process all the meshes spread on multiple frames + //Time to process all the meshes spread on multiple frames. Thread.Sleep(5); } - else + else //If there are meshes that were collected but not processed yet. Happens if the last update took too long to process. { - //If remain meshes it checks every 5ms + //Check every 5ms if the meshes are done being processed. Thread.Sleep(5); } @@ -491,7 +542,7 @@ private void UpdateMesh() } /// - /// Destroy all submesh. + /// Destroys all submeshes. /// private void ClearMeshes() { @@ -499,14 +550,15 @@ private void ClearMeshes() { GameObject.Destroy(child.gameObject); } - zedSpatialMapping.Clear(); + spatialMappingHelper.Clear(); } /// - /// Measure time. If the computational time is over the limit, all the meshes not processed will be done in the next frame + /// Measures time since the provided start time. Used in UpdateMeshMainthread() to check if computational time for mesh updates + /// has exceeded the MAX_TIME time limit (usually 5ms), so that it can hold off processing remaining meshes until the next frame. /// - /// - /// + /// Time.realtimeSinceStartup value when the process began. + /// True if more than MAX_TIME has elapsed since startTimeMS. private bool GoneOverTimeBudget(int startTimeMS) { return (Time.realtimeSinceStartup * 1000) - startTimeMS > MAX_TIME; @@ -514,20 +566,24 @@ private bool GoneOverTimeBudget(int startTimeMS) /// - /// Update the unity mesh with the last data retrieved from the ZED, create new submesh if needed. - /// Launch the OnMeshUpdate event when the update is done. + /// Update the Unity mesh with the last data retrieved from the ZED, creating a new submesh if needed. + /// Also launches the OnMeshUpdate event when the update is finished. + /// If true, caps time spent on updating meshes each frame, leaving 'leftover' meshes for the next frame. /// private void UpdateMeshMainthread(bool spreadUpdateOverTime = true) { - int startTimeMS = (int)(Time.realtimeSinceStartup * 1000); + //Cache the start time so we can measure how long this function is taking. + //We'll check when updating the submeshes so that if it takes too long, we'll stop updating until the next frame. + int startTimeMS = (int)(Time.realtimeSinceStartup * 1000); int indexUpdate = 0; - lock (lockScanning) + lock (lockScanning) //Don't update if another thread is accessing. { if (updatedTexture) { spreadUpdateOverTime = false; } - //Set the offset of the buffers to the offset of the last frame + + //Set the offset of the buffers to the offset of the last frame. int verticesOffset = 0, trianglesOffset = 0, uvsOffset = 0; if (remainMeshes && spreadUpdateOverTime) { @@ -537,22 +593,21 @@ private void UpdateMeshMainthread(bool spreadUpdateOverTime = true) indexUpdate = indexLastFrame; } - //Clear all the mesh and process the last ones + //Clear all existing meshes and process the last ones. if (updatedTexture) { ClearMeshes(); - zedSpatialMapping.SetMeshAndTexture(); + spatialMappingHelper.SetMeshAndTexture(); ZEDMeshRenderer.isTextured = isTextured; } - //Process the last meshes - for (; indexUpdate < zedSpatialMapping.NumberUpdatedSubMesh; indexUpdate++) + //Process the last meshes. + for (; indexUpdate < spatialMappingHelper.NumberUpdatedSubMesh; indexUpdate++) { - - zedSpatialMapping.SetMesh(indexUpdate, ref verticesOffset, ref trianglesOffset, ref uvsOffset, holder.transform, updatedTexture); - if (spreadUpdateOverTime && GoneOverTimeBudget(startTimeMS)) + spatialMappingHelper.SetMesh(indexUpdate, ref verticesOffset, ref trianglesOffset, ref uvsOffset, holder.transform, updatedTexture); + if (spreadUpdateOverTime && GoneOverTimeBudget(startTimeMS)) //Check if it's taken too long this frame. { - remainMeshes = true; + remainMeshes = true; //It has. Set this flag so we know to pick up where we left off next frame. break; } } @@ -565,8 +620,8 @@ private void UpdateMeshMainthread(bool spreadUpdateOverTime = true) indexLastFrame = 0; } - //If all the meshes are processed - if ((indexUpdate == zedSpatialMapping.NumberUpdatedSubMesh) || zedSpatialMapping.NumberUpdatedSubMesh == 0) + //If all the meshes have been updated, reset values used to process 'leftover' meshes and get more data from the ZED. + if ((indexUpdate == spatialMappingHelper.NumberUpdatedSubMesh) || spatialMappingHelper.NumberUpdatedSubMesh == 0) { verticesOffsetLastFrame = 0; trianglesOffsetLastFrame = 0; @@ -576,8 +631,8 @@ private void UpdateMeshMainthread(bool spreadUpdateOverTime = true) meshUpdated = false; zedCamera.RequestMesh(); } - //If it remains meshes, we save the offsets - else if (indexUpdate != zedSpatialMapping.NumberUpdatedSubMesh) + //If some meshes still need updating, we'll save the offsets so we know where to start next frame. + else if (indexUpdate != spatialMappingHelper.NumberUpdatedSubMesh) { remainMeshes = true; indexLastFrame = indexUpdate + 1; @@ -591,10 +646,10 @@ private void UpdateMeshMainthread(bool spreadUpdateOverTime = true) if (OnMeshUpdate != null) { - OnMeshUpdate(); + OnMeshUpdate(); //Call the event if it has at least one listener. } - //The update texture is done in one pass + //The texture update is done in one pass, so this is only called once after the mesh has stopped scanning. if (updatedTexture) { DisableSpatialMapping(); @@ -613,7 +668,8 @@ private void UpdateMeshMainthread(bool spreadUpdateOverTime = true) } /// - /// Display or hide the mesh. + /// Changes the visibility state of the meshes. + /// This is what's called when the Hide/Display Mesh button is clicked in the Inspector. /// /// If true, the mesh will be displayed, else it will be hide. public void SwitchDisplayMeshState(bool newDisplayState) @@ -622,7 +678,7 @@ public void SwitchDisplayMeshState(bool newDisplayState) } /// - /// Pause or resume the spatial mapping. If the spatial mapping is not enable, nothing will happend. + /// Pauses or resumes spatial mapping. If the spatial mapping is not enabled, nothing will happen. /// /// If true, the spatial mapping will be paused, else it will be resumed. public void SwitchPauseState(bool newPauseState) @@ -632,8 +688,8 @@ public void SwitchPauseState(bool newPauseState) } /// - /// Update the mesh collider with the current mesh so it can handle physic. - /// Calling it is time consuming. + /// Update the mesh collider with the current mesh so it can handle physics. + /// Calling it is slow, so it's only called after a scan is finished (or loaded). /// public void UpdateMeshCollider(bool timeSlicing = false) { @@ -644,7 +700,7 @@ public void UpdateMeshCollider(bool timeSlicing = false) } lock (lockScanning) { - zedSpatialMapping.UpdateMeshCollider(ChunkList); + spatialMappingHelper.UpdateMeshCollider(ChunkList); } if (OnMeshReady != null) { @@ -653,6 +709,10 @@ public void UpdateMeshCollider(bool timeSlicing = false) running = false; } + /// + /// Properly clears existing scan data when the application is closed. + /// Called by OnApplicationQuit() when the application closes. + /// public void Dispose() { if (scanningThread != null) @@ -666,15 +726,15 @@ public void Dispose() } /// - /// Disable the ZED's spatial mapping. - /// The mesh will no longer be updated, but it is not delete. + /// Disable the ZED's spatial mapping. The mesh will no longer be updated, but it is not deleted. + /// This gets called in Update() if the user requested a stop, and will execute once the scanning thread is free. /// private void DisableSpatialMapping() { lock (lockScanning) { updateThreadRunning = false; - zedSpatialMapping.DisableSpatialMapping(); + spatialMappingHelper.DisableSpatialMapping(); scanningInitState = sl.ERROR_CODE.FAILURE; spatialMappingRequested = false; @@ -682,7 +742,8 @@ private void DisableSpatialMapping() } /// - /// Save the mesh as an obj file and the area database as an area file. It can be quite time comsuming if you mapped a large area. + /// Save the mesh as an .obj, .ply or .bin file, and the area database as an .area file. + /// This can be quite time-comsuming if you mapped a large area. /// public bool SaveMesh(string meshFilePath = "Assets/ZEDMesh.obj") { @@ -690,16 +751,16 @@ public bool SaveMesh(string meshFilePath = "Assets/ZEDMesh.obj") if (updateThreadRunning) { - StopStatialMapping(); + StopStatialMapping(); //Stop the mapping if it hasn't stopped already. } lock (lockScanning) { - string[] splitedPath = meshFilePath.Split('.'); - if (splitedPath[splitedPath.Length - 1].Contains("obj")) + string[] splitPath = meshFilePath.Split('.'); + if (splitPath[splitPath.Length - 1].Contains("obj")) { err = zedCamera.SaveMesh(meshFilePath, sl.MESH_FILE_FORMAT.OBJ); } - else if (splitedPath[splitedPath.Length - 1].Contains("ply")) + else if (splitPath[splitPath.Length - 1].Contains("ply")) { err = zedCamera.SaveMesh(meshFilePath, sl.MESH_FILE_FORMAT.BIN); } @@ -715,8 +776,11 @@ public bool SaveMesh(string meshFilePath = "Assets/ZEDMesh.obj") } /// - /// Load the mesh and the corresponding area file if it exists. It can be quite time comsuming if you mapped a large area. - /// If there are no areas found, the mesh will not be loaded + /// Loads the mesh and the corresponding area file if it exists. It can be quite time-comsuming if you mapped a large area. + /// Note that if there are no .area files found in the same folder, the mesh will not be loaded either. + /// Loading a mesh this way also loads relevant data into buffers, so it's as if a scan was just finished + /// rather than a mesh asset being dropped into Unity. + /// True if loaded successfully, otherwise flase. /// public bool LoadMesh(string meshFilePath = "ZEDMesh.obj") { @@ -724,22 +788,20 @@ public bool LoadMesh(string meshFilePath = "ZEDMesh.obj") { OnMeshStarted(); } - //If a spatail mapping have started, disable it + //If spatial mapping has started, disable it. DisableSpatialMapping(); //Find and load the area string basePath = meshFilePath.Substring(0, meshFilePath.LastIndexOf(".")); if(!System.IO.File.Exists(basePath + ".area")) { Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_BASE_AREA_NOT_FOUND)); - return false; } zedCamera.DisableTracking(); Quaternion quat = Quaternion.identity; Vector3 tr = Vector3.zero; - if (zedCamera.EnableTracking(ref quat, ref tr, true,false, System.IO.File.Exists(basePath + ".area") ? basePath + ".area" : "") != sl.ERROR_CODE.SUCCESS) + if (zedCamera.EnableTracking(ref quat, ref tr, true, false, System.IO.File.Exists(basePath + ".area") ? basePath + ".area" : "") != sl.ERROR_CODE.SUCCESS) { Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_NOT_INITIALIZED)); - return false; } updateTexture = false; @@ -748,33 +810,31 @@ public bool LoadMesh(string meshFilePath = "ZEDMesh.obj") lock (lockScanning) { ClearMeshes(); - meshUpdatedLoad = zedSpatialMapping.LoadMesh(meshFilePath); + meshUpdatedLoad = spatialMappingHelper.LoadMesh(meshFilePath); if (meshUpdatedLoad) { - //Checks if a texture exists - if (zedSpatialMapping.GetWidthTexture() != -1) + //Checks if a texture exists. + if (spatialMappingHelper.GetWidthTexture() != -1) { updateTexture = true; updatedTexture = true; } - //Retrieves the mesh sizes to be updated in the unity's buffer later + //Retrieves the mesh sizes to be updated in the Unity's buffer later. if (!updateTexture) { - zedSpatialMapping.RetrieveMesh(); + spatialMappingHelper.RetrieveMesh(); } } } - if (meshUpdatedLoad) { + //Update the buffer on Unity's side. + UpdateMeshMainthread(false); - //Update the buffer on the unity's side - UpdateMeshMainthread(false); - - //Add colliders and scan for gravity + //Add colliders and scan for gravity. if (hasColliders) { if (!ZEDManager.IsStereoRig && gravityEstimation != Vector3.zero) @@ -793,28 +853,33 @@ public bool LoadMesh(string meshFilePath = "ZEDMesh.obj") if (OnMeshReady != null) { - OnMeshReady(); + OnMeshReady(); //Call the event if it has at least one listener. } - return true; + return true; } return false; } /// - /// Filters the mesh with the current parameter. + /// Filters the mesh with the current filtering parameters. + /// This reduces the total number of faces. More filtering means fewer faces. /// public void FilterMesh() { - lock (lockScanning) + lock (lockScanning) //Wait for the thread to be available. { - zedSpatialMapping.FilterMesh(filterParameters); - zedSpatialMapping.ResizeMesh(); - zedSpatialMapping.RetrieveMesh(); + spatialMappingHelper.FilterMesh(filterParameters); + spatialMappingHelper.ResizeMesh(); + spatialMappingHelper.RetrieveMesh(); meshUpdated = true; } } + /// + /// Begin mesh filtering, and consolidate chunks into a reasonably low number when finished. + /// + /// void PostProcessMesh(bool filter = true) { isFiltering = true; @@ -826,31 +891,35 @@ void PostProcessMesh(bool filter = true) } /// - /// Reshape the mesh to get less chunks + /// Consolidates meshes to get fewer chunks - one for every MAX_SUBMESH vertices. Then applies to + /// actual meshes in Unity. /// public void MergeChunks() { lock (lockScanning) { - zedSpatialMapping.MergeChunks(); - zedSpatialMapping.ResizeMesh(); - zedSpatialMapping.RetrieveMesh(); + spatialMappingHelper.MergeChunks(); + spatialMappingHelper.ResizeMesh(); + spatialMappingHelper.RetrieveMesh(); meshUpdated = true; } isFiltering = false; isFilteringOver = true; } + /// + /// Multi-threaded component of ApplyTexture(). Filters, then updates the mesh once, but as + /// updateTexture is set to true when this is called, UpdateMesh() will also handle applying the texture. + /// void ApplyTextureThreaded() { - FilterMesh(); UpdateMesh(); } /// - /// Start the texturing of the mesh, this will stop the spatial mapping. + /// Stops the spatial mapping and begins the final processing, including adding texture. /// public bool ApplyTexture() { @@ -868,7 +937,7 @@ public bool ApplyTexture() } /// - /// Stop the spatial mapping + /// Stop the spatial mapping and calls appropriate functions to process the final mesh. /// private void Stop() { @@ -894,11 +963,11 @@ private void Stop() } - SwitchDisplayMeshState(true); + SwitchDisplayMeshState(true); //Make it default to visible. } /// - /// Returns true from the enable tracking until the post-process is done. + /// Returns true from the moment a scan has started until the post-process is finished. /// /// public bool IsRunning() @@ -907,23 +976,24 @@ public bool IsRunning() } /// - /// Stop the spatial mapping (filter the mesh, disable the spatial mapping and update the mesh collider). The stop will occured after all the post-process. + /// Sets a flag that will cause spatial mapping to stop at the next Update() call after all meshes already retrieved from the ZED are applied. /// public void StopStatialMapping() { stopWanted = true; } - //To draw the meshes in the editor with a double pass shader + /// + /// Used by Unity to draw the meshes in the editor with a double pass shader. + /// #if UNITY_EDITOR private void OnDrawGizmos() { Gizmos.color = colorMesh; - - if (!IsRunning() && zedSpatialMapping != null && zedSpatialMapping.chunks.Count != 0 && display) + if (!IsRunning() && spatialMappingHelper != null && spatialMappingHelper.chunks.Count != 0 && display) { - foreach (var submesh in zedSpatialMapping.chunks) + foreach (var submesh in spatialMappingHelper.chunks) { if (submesh.Value.proceduralMesh.mesh != null) { @@ -936,40 +1006,83 @@ private void OnDrawGizmos() /// - /// Low level spatial mapping class. + /// Low-level spatial mapping class. Calls SDK wrapper functions to get mesh data and applies it to Unity meshes. + /// Functions are usually called from ZEDSpatialMapping, but buffer data is held within. + /// Note that some values are updated directly from the ZED wrapper dll, so such assignments aren't visible in the plugin. /// private class ZEDSpatialMappingHelper { - + /// + /// Reference to the ZEDCamera instance. Used to call SDK functions. + /// private sl.ZEDCamera zedCamera; /// - /// Number of vertices per chunk. Best value to get few chunks and to update them quickly + /// Maximum number of chunks. It's best to get relatively few chunks and to update them quickly. /// - private const int MAX_SUBMESH = 10000; + private const int MAX_SUBMESH = 1000; - /*** Number of vertices/uvs/indices per chunk***/ + /*** Number of vertices/triangles/indices per chunk***/ + /// + /// Total vertices in each chunk/submesh. + /// private int[] numVerticesInSubmesh = new int[MAX_SUBMESH]; + /// + /// Total triangles in each chunk/submesh. + /// private int[] numTrianglesInSubmesh = new int[MAX_SUBMESH]; + /// + /// Total indices per chunk/submesh. + /// private int[] UpdatedIndices = new int[MAX_SUBMESH]; /*** Number of vertices/uvs/indices at the moment**/ + /// + /// Vertex count in current submesh. + /// private int numVertices = 0; + /// + /// Triangle point counds in current submesh. (Every three values are the indexes of the three vertexes that make up one triangle) + /// private int numTriangles = 0; + /// + /// How many submeshes were updated. + /// private int numUpdatedSubmesh = 0; /*** The current data in the current submesh***/ + /// + /// Vertices of the current submesh. + /// private Vector3[] vertices; + /// + /// UVs of the current submesh. + /// private Vector2[] uvs; + /// + /// Triangles of the current submesh. (Each int refers to the index of a vertex) + /// private int[] triangles; + /// + /// Width and height of the mesh texture, if any. + /// private int[] texturesSize = new int[2]; - + /// + /// Dictionary of all existing chunks. + /// public Dictionary chunks = new Dictionary(MAX_SUBMESH); + /// + /// Material with real-world texture, applied to the mesh when Texturing (isTextured) is enabled. + /// private Material materialTexture; + /// + /// Material used to draw the mesh. Applied to chunks during the scan, and replaced with materialTexture + /// only if Texturing (isTextured) is enabled. + /// private Material materialMesh; /// - /// Number of chunks updated + /// Public accessor for the number of chunks that have been updated. /// public int NumberUpdatedSubMesh { @@ -977,7 +1090,7 @@ public int NumberUpdatedSubMesh } /// - /// Gets the spatial mapping material to draw + /// Gets the material used to draw spatial mapping meshes without real-world textures. /// /// public Material GetMaterialSpatialMapping() @@ -985,6 +1098,11 @@ public Material GetMaterialSpatialMapping() return materialMesh; } + /// + /// Constructor. Gets the ZEDCamera instance and sets materials used on the meshes. + /// + /// + /// public ZEDSpatialMappingHelper(Material materialTexture, Material materialMesh) { zedCamera = sl.ZEDCamera.GetInstance(); @@ -993,7 +1111,7 @@ public ZEDSpatialMappingHelper(Material materialTexture, Material materialMesh) } /// - /// Updates the range and resolution to match the specified preset. + /// Updates the range to match the specified preset. /// static public float ConvertRangePreset(RANGE rangePreset) { @@ -1014,7 +1132,7 @@ static public float ConvertRangePreset(RANGE rangePreset) } /// - /// Update the range and resolution to match the specified preset. + /// Updates the resolution to match the specified preset. /// static public float ConvertResolutionPreset(RESOLUTION resolutionPreset) { @@ -1034,7 +1152,7 @@ static public float ConvertResolutionPreset(RESOLUTION resolutionPreset) } /// - /// Enables the spatial mapping + /// Tells the ZED SDK to begin spatial mapping. /// /// @@ -1044,7 +1162,7 @@ public sl.ERROR_CODE EnableSpatialMapping(float resolutionMeter, float maxRangeM } /// - /// Disable the spatial mapping + /// Tells the ZED SDK to stop spatial mapping. /// public void DisableSpatialMapping() { @@ -1056,10 +1174,9 @@ public void DisableSpatialMapping() /// public ZEDSpatialMapping.Chunk CreateNewMesh(int i, Material meshMat, Transform holder) { - //The chunk + //Initialize the chunk and create a GameObject for it. ZEDSpatialMapping.Chunk chunk = new ZEDSpatialMapping.Chunk(); chunk.o = GameObject.CreatePrimitive(PrimitiveType.Quad); - //subMesh.o.hideFlags = HideFlags.HideAndDontSave; chunk.o.layer = sl.ZEDCamera.TagOneObject; chunk.o.GetComponent().sharedMesh = null; chunk.o.name = "Chunk" + chunks.Count; @@ -1067,10 +1184,10 @@ public ZEDSpatialMapping.Chunk CreateNewMesh(int i, Material meshMat, Transform chunk.o.transform.localRotation = Quaternion.identity; Mesh m = new Mesh(); - m.MarkDynamic(); + m.MarkDynamic(); //Allows it to be updated regularly without performance issues. chunk.mesh = m; - //Set the options of the mesh (no shadows, no reflections, no lights) + //Set graphics settings to not treat the chunk like a physical object (no shadows, no reflections, no lights, etc.). MeshRenderer meshRenderer = chunk.o.GetComponent(); meshRenderer.material = meshMat; meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; @@ -1079,23 +1196,25 @@ public ZEDSpatialMapping.Chunk CreateNewMesh(int i, Material meshMat, Transform meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; meshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; - //Sets the positions and parent of the chunk + //Sets the position and parent of the chunk. chunk.o.transform.parent = holder; chunk.o.layer = sl.ZEDCamera.TagOneObject; - //Add the chunk to the list + //Add the chunk to the dictionary. chunk.proceduralMesh.mesh = chunk.o.GetComponent(); chunks.Add(i, chunk); return chunk; } /// - /// Set the mesh collider to each chunck + /// Adds a MeshCollider to each chunk for physics. This is time-consuming, so it's only called + /// once scanning is finished and the final mesh is being processed. /// public void UpdateMeshCollider(List listMeshes, int startIndex = 0) { - List idsToDestroy = new List(); - //Update each mesh with a collider + List idsToDestroy = new List(); //List of meshes that are too small for colliders and will be destroyed. + + //Update each mesh with a collider. for (int i = startIndex; i < listMeshes.Count; ++i) { var submesh = listMeshes[i]; @@ -1105,7 +1224,8 @@ public void UpdateMeshCollider(List listMeshes, int sta { m = submesh.o.AddComponent(); } - //If a mesh is degenerated it should be destroyed + + //If a mesh has 2 or fewer vertices, it's useless, so queue it up to be destroyed. Mesh tempMesh = submesh.o.GetComponent().sharedMesh; if (tempMesh.vertexCount < 3) { @@ -1119,18 +1239,17 @@ public void UpdateMeshCollider(List listMeshes, int sta m.sharedMesh.RecalculateBounds(); } - //Delay id destruction + //Destroy all useless meshes now that we've iterated through all the meshes. for (int i = 0; i < idsToDestroy.Count; ++i) { GameObject.Destroy(chunks[idsToDestroy[i]].o); chunks.Remove(idsToDestroy[i]); } - Clear(); - + Clear(); //Clear the buffer data now that we have Unity meshes. } /// - /// Refresh the size of the texture and prepare the uvs + /// Tells the ZED SDK to calculate the size of the texture and the UVs. /// public void ApplyTexture() { @@ -1138,7 +1257,7 @@ public void ApplyTexture() } /// - /// Update the mesh + /// Tells the ZED SDK to update its internal mesh from spatial mapping. The resulting mesh will later be retrieved with RetrieveMesh(). /// public void UpdateMesh() { @@ -1147,17 +1266,16 @@ public void UpdateMesh() } /// - /// Retrieve the mesh vertices and triangles + /// Retrieves the mesh vertices and triangles from the ZED SDK. This must be called after UpdateMesh() has been called. + /// Note that the actual assignment to vertices and triangles happens from within the wrapper .dll via pointers, not a C# script. /// public void RetrieveMesh() { zedCamera.RetrieveMesh(vertices, triangles, MAX_SUBMESH, null, System.IntPtr.Zero); } - - /// - /// Clear all the current data + /// Clear the current buffer data. /// public void Clear() { @@ -1172,29 +1290,26 @@ public void Clear() } /// - /// Set the mesh + /// Process data from a submesh retrieved from the ZED SDK into a chunk, which includes a GameObject and visible mesh. /// - /// Index which is going to be updated - /// Starting index in the vertices stack - /// Starting index in the triangles stack - /// Starting index in the uvs index - /// - /// - /// - /// - /// + /// Index of the submesh/chunk to be updated. + /// Starting index in the vertices stack. + /// Starting index in the triangles stack. + /// Starting index in the UVs stack. + /// Transform of the holder object to which all chunks are parented. + /// True if the world texture has been updated so we know to update UVs. public void SetMesh(int indexUpdate, ref int verticesOffset, ref int trianglesOffset, ref int uvsOffset, Transform holder, bool updatedTex) { ZEDSpatialMapping.Chunk subMesh; int updatedIndex = UpdatedIndices[indexUpdate]; - if (!chunks.TryGetValue(updatedIndex, out subMesh)) + if (!chunks.TryGetValue(updatedIndex, out subMesh)) //Use the existing chunk/submesh if already in the dictionary. Otherwise, make a new one. { subMesh = CreateNewMesh(updatedIndex, materialMesh, holder); } Mesh currentMesh = subMesh.mesh; ZEDSpatialMapping.ProceduralMesh dynamicMesh = subMesh.proceduralMesh; - //Check if allocated, if the size is the same do not allocate + //If the dynamicMesh's triangle and vertex arrays are unassigned or are the wrong size, redo the array. if (dynamicMesh.triangles == null || dynamicMesh.triangles.Length != 3 * numTrianglesInSubmesh[indexUpdate]) { dynamicMesh.triangles = new int[3 * numTrianglesInSubmesh[indexUpdate]]; @@ -1204,20 +1319,20 @@ public void SetMesh(int indexUpdate, ref int verticesOffset, ref int trianglesOf dynamicMesh.vertices = new Vector3[numVerticesInSubmesh[indexUpdate]]; } - //Clear the old data + //Clear the old mesh data. currentMesh.Clear(); - //Copy the new data + //Copy data retrieved from the ZED SDK into the ProceduralMesh buffer in the current chunk. System.Array.Copy(vertices, verticesOffset, dynamicMesh.vertices, 0, numVerticesInSubmesh[indexUpdate]); verticesOffset += numVerticesInSubmesh[indexUpdate]; - System.Buffer.BlockCopy(triangles, trianglesOffset * sizeof(int), dynamicMesh.triangles, 0, 3 * numTrianglesInSubmesh[indexUpdate] * sizeof(int));//Block copy has better performance than Array + System.Buffer.BlockCopy(triangles, trianglesOffset * sizeof(int), dynamicMesh.triangles, 0, 3 * numTrianglesInSubmesh[indexUpdate] * sizeof(int)); //Block copy has better performance than Array. trianglesOffset += 3 * numTrianglesInSubmesh[indexUpdate]; currentMesh.vertices = dynamicMesh.vertices; currentMesh.SetTriangles(dynamicMesh.triangles, 0, false); dynamicMesh.mesh.sharedMesh = currentMesh; - //If texture add UVS + //If textured, add UVs. if (updatedTex) { Vector2[] localUvs = new Vector2[numVerticesInSubmesh[indexUpdate]]; @@ -1229,18 +1344,19 @@ public void SetMesh(int indexUpdate, ref int verticesOffset, ref int trianglesOf } /// - /// Set the texture and mesh (vertices, triangles, and uvs) + /// Retrieves the entire mesh and texture (vertices, triangles, and uvs) from the ZED SDK. + /// Differs for normal retrieval as the UVs and texture are retrieved. + /// This is only called after scanning has been stopped, and only if Texturing is enabled. /// public void SetMeshAndTexture() { - //If the texture is too large, impossible to add a texture to the mesh + //If the texture is too large, it's impossible to add the texture to the mesh. if (texturesSize[0] > 8192) return; Texture2D textureMesh = new Texture2D(texturesSize[0], texturesSize[1], TextureFormat.RGB24, false); if (textureMesh != null) { - System.IntPtr texture = textureMesh.GetNativeTexturePtr(); materialTexture.SetTexture("_MainTex", textureMesh); @@ -1248,14 +1364,14 @@ public void SetMeshAndTexture() uvs = new Vector2[numVertices]; triangles = new int[3 * numTriangles]; - zedCamera.RetrieveMesh(vertices, triangles, MAX_SUBMESH, uvs, texture); + zedCamera.RetrieveMesh(vertices, triangles, MAX_SUBMESH, uvs, texture); } } /// - /// Load the mesh from a file path and allocate the buffers + /// Loads a mesh from a file path and allocates the buffers accordingly. /// - /// + /// Path to the mesh file. /// public bool LoadMesh(string meshFilePath) { @@ -1267,22 +1383,22 @@ public bool LoadMesh(string meshFilePath) } /// - /// Get the texture width, if this one is over 8k, the texture will not be taken. + /// Gets the width of the scanned texture file. Note that if this is over 8k, the texture will not be taken. /// - /// + /// Texture width in pixels. public int GetWidthTexture() { return texturesSize[0]; } /// - /// Resize the mesh buffer + /// Resize the mesh buffer according to how many vertices are needed by the current submesh/chunk. /// public void ResizeMesh() { if (vertices.Length < numVertices) { - vertices = new Vector3[numVertices * 2]; // Better allocate than resize, faster + vertices = new Vector3[numVertices * 2]; //Allocation is faster than resizing. } if (triangles.Length < 3 * numTriangles) @@ -1292,16 +1408,17 @@ public void ResizeMesh() } /// - /// Filter a mesh with predefined parameters + /// Filters the mesh with predefined parameters. /// - /// + /// Filter setting. A higher setting results in fewer faces. public void FilterMesh(sl.FILTER filterParameters) { zedCamera.FilterMesh(filterParameters, numVerticesInSubmesh, numTrianglesInSubmesh, ref numUpdatedSubmesh, UpdatedIndices, ref numVertices, ref numTriangles, MAX_SUBMESH); } /// - /// Reshape the chunks to get less + /// Tells the ZED SDK to consolidate the chunks into a smaller number of large chunks. + /// Useful because having many small chunks is more performant for scanning, but fewer large chunks are otherwise easier to work with. /// public void MergeChunks() { diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMappingManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMappingManager.cs index d8fc4c0f..163ac471 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMappingManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMappingManager.cs @@ -8,88 +8,98 @@ #endif /// -/// Contols the ZEDSpatialMapping and hides its implementation +/// High level interface for the ZED's Spatial Mapping features. Allows you to scan your environment into a 3D mesh. +/// The scan will appear as a set of "chunk" meshes under a GameObject called "[ZED Mesh Holder] created at runtime. +/// The mesh can be used once scanning is finished after a brief finalizing/filtering/texturing period, and saved into +/// an .obj, .ply or .bin if desired. It will also get a MeshCollider cadded to it, so that virtual objects can collide with it. +/// Saving a scan made with this class also saves an .area file in the same location that can be used by the ZED's Spatial Memory +/// feature for better tracking localization. +/// Most of the spatial mapping implementation is handled in ZEDSpatialMapping.cs, but this class simplifies its use. +/// For more information and a tutorial, see our documentation: https://docs.stereolabs.com/mixed-reality/unity/spatial-mapping-unity/ /// [DisallowMultipleComponent] public class ZEDSpatialMappingManager : MonoBehaviour { - - - /// - /// Current resolution, a higher resolution create more meshes + /// Resolution setting for the scan. A higher resolution creates more submeshes and uses more memory, but is more accurate. /// public ZEDSpatialMapping.RESOLUTION resolution_preset = ZEDSpatialMapping.RESOLUTION.MEDIUM; /// - /// The range of the spatial mapping, how far the depth is taken into account + /// Maximum distance geometry can be from the camera to be scanned. Geometry scanned from farther away will be less accurate. /// public ZEDSpatialMapping.RANGE range_preset = ZEDSpatialMapping.RANGE.MEDIUM; /// - /// Flag if filtering is needed + /// Whether mesh filtering is needed. /// public bool isFilteringEnable = false; /// - /// Falg is the textures will be created and applied + /// Whether surface textures will be scanned and applied. Note that texturing will add further delay to the post-scan finalizing period. /// public bool isTextured = false; /// - /// Flag to save when spatial mapping is over + /// Whether to save the mesh .obj and .area files once the scan is finished. /// public bool saveWhenOver = false; /// - /// Path to save the .obj and the .area + /// Path to save the .obj and .area files. /// public string meshPath = "Assets/ZEDMesh.obj"; /// - /// The parameters of filtering + /// Filtering setting. More filtering results in fewer faces in the mesh, reducing both file size and accuracy. /// public sl.FILTER filterParameters; /// - /// The core of spatial mapping + /// Instance of the ZEDSpatialMapping class that handles the actual spatial mapping implementation within Unity. /// private ZEDSpatialMapping spatialMapping; + + /// + /// The scene's ZEDManager instance. Usually attached to the ZED rig root object (ZED_Rig_Mono or ZED_Rig_Stereo). + /// private ZEDManager manager; + /// + /// Fills the manager reference and instantiates ZEDSpatialMapping. + /// private void Start() { - manager = GameObject.FindObjectOfType(typeof(ZEDManager)) as ZEDManager; + manager = ZEDManager.Instance; spatialMapping = new ZEDSpatialMapping(transform, sl.ZEDCamera.GetInstance(), manager); } /// - /// Is the spatial mapping running + /// Whether the spatial mapping is currently scanning. /// public bool IsRunning {get { return spatialMapping!= null ? spatialMapping.IsRunning(): false; }} /// - /// List of the submeshes processed, it is filled only when "StopSpatialMapping" is called + /// List of the processed submeshes. This list isn't filled until StopSpatialMapping() is called. /// public List ChunkList { get { return spatialMapping != null ? spatialMapping.ChunkList : null; } } /// - /// Is the update thread running, the thread is stopped before the post process + /// Whether the mesh update thread is running. /// public bool IsUpdateThreadRunning { get { return spatialMapping != null ? spatialMapping.IsUpdateThreadRunning: false; } } /// - /// Is the spatial mapping process is stopped + /// Whether the spatial mapping was running but has been paused (not stopped) by the user. /// public bool IsPaused { get { return spatialMapping != null ? spatialMapping.IsPaused :false; } } /// - /// Is the texturing is running + /// Whether the mesh is in the texturing stage of finalization. /// public bool IsTexturingRunning { get { return spatialMapping != null ? spatialMapping.IsTexturingRunning : false; } } - private void OnEnable() { ZEDSpatialMapping.OnMeshReady += SpatialMappingHasStopped; @@ -100,12 +110,18 @@ private void OnDisable() ZEDSpatialMapping.OnMeshReady -= SpatialMappingHasStopped; } + /// + /// Saves the mesh once it's finished, if saveWhenOver is set to true. + /// void SpatialMappingHasStopped() { if (saveWhenOver) SaveMesh(meshPath); } + /// + /// Tells ZEDSpatialMapping to begin a new scan. This clears the previous scan from the scene if there is one. + /// public void StartSpatialMapping() { transform.position = Vector3.zero; @@ -115,89 +131,143 @@ public void StartSpatialMapping() } /// - /// Stop the current spatial mapping, the current mapping will be processed to add a mesh collider, and events will be called + /// Ends the current spatial mapping. Once called, the current mesh will be filtered, textured (if enabled) and saved (if enabled), + /// and a mesh collider will be added. /// public void StopSpatialMapping() { spatialMapping.StopStatialMapping(); } + /// + /// Updates the filtering parameters and call the ZEDSpatialMapping instance's Update() function. + /// private void Update() { if (spatialMapping != null) { spatialMapping.filterParameters = filterParameters; - spatialMapping.Update(); + spatialMapping.Update(); //As ZEDSpatialMapping doesn't inherit from Monobehaviour, this doesn't happen automatically. } } + /// + /// Properly clears existing scan data when the application is closed. + /// private void OnApplicationQuit() { spatialMapping.Dispose(); } /// - /// Display the mesh + /// Toggles whether to display the mesh or not. /// - /// + /// True to make the mesh visible, false to make it invisible. public void SwitchDisplayMeshState(bool state) { spatialMapping.SwitchDisplayMeshState(state); } /// - /// Pause the computation of the mesh + /// Pauses the current scan. /// - /// + /// True to pause the scanning, false to unpause it. public void SwitchPauseState(bool state) { spatialMapping.SwitchPauseState(state); } /// - /// Save the mesh in a file. The saving will disable the spatial mapping and register and area memory. - /// May take some time + /// Saves the mesh into a 3D model (.obj, .ply or .bin) file. Also saves an .area file for spatial memory for better tracking. + /// Calling this will end the spatial mapping if it's running. Note it can take a significant amount of time to finish. /// - /// - /// + /// Path where the mesh and .area files will be saved. public bool SaveMesh(string meshPath = "ZEDMeshObj.obj") { return spatialMapping.SaveMesh(meshPath); } /// - /// Load the mesh from a file + /// Loads a mesh and spatial memory data from a file. + /// If scanning is running, it will be stopped. Existing scans in the scene will be cleared. /// - /// - /// + /// Path to the 3D mesh file (.obj, .ply or .bin) to load. + /// True if successfully loaded, false otherwise. public bool LoadMesh(string meshPath = "ZEDMeshObj.obj") { + //Cache the save setting and set to false, to avoid overwriting the mesh file during the load. + bool oldSaveWhenOver = saveWhenOver; + saveWhenOver = false; + manager.gravityRotation = Quaternion.identity; spatialMapping.SetMeshRenderer(); - return spatialMapping.LoadMesh(meshPath); + bool loadresult = spatialMapping.LoadMesh(meshPath); + + saveWhenOver = oldSaveWhenOver; //Restoring old setting. + return loadresult; } } #if UNITY_EDITOR - +/// +/// Custom Inspector screen for ZEDSpatialMappingManager. +/// Displays values in an organized manner, and adds buttons for starting/stopping spatial +/// mapping and hiding/displaying the resulting mesh. +/// [CustomEditor(typeof(ZEDSpatialMappingManager))] public class ZEDSpatialMappingEditor : Editor { + /// + /// The ZEDSpatialMappingManager component this editor instance is editing. + /// private ZEDSpatialMappingManager spatialMapping; + /// + /// Layout option used to draw the '...' button for opening a File Explorer window to find a mesh file. + /// private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) }; + /// + /// Text on the mesh visibility button. Switches between 'Hide Mesh' and 'Display Mesh'. + /// private string displayText = "Hide Mesh"; + + ///Serialized properties used to apply and save changes. + + /// + /// Serialized version of ZEDSpatialMappingManager's range_preset property. + /// private SerializedProperty range; + /// + /// Serialized version of ZEDSpatialMappingManager's resolution_preset property. + /// private SerializedProperty resolution; + /// + /// Serialized version of ZEDSpatialMappingManager's isFilteringEnable property. + /// private SerializedProperty isFilteringEnable; + /// + /// Serialized version of ZEDSpatialMappingManager's filterParameters property. + /// private SerializedProperty filterParameters; + /// + /// Serialized version of ZEDSpatialMappingManager's isTextured property. + /// private SerializedProperty saveWhenOver; + /// + /// Serialized version of ZEDSpatialMappingManager's saveWhenOver property. + /// private SerializedProperty isTextured; + /// + /// Serialized version of ZEDSpatialMappingManager's meshPath property. + /// private SerializedProperty meshPath; + /// + /// Public accessor to the ZEDSpatialMappingManager component this editor instance is editing. + /// private ZEDSpatialMappingManager Target { get { return (ZEDSpatialMappingManager)target; } @@ -205,6 +275,7 @@ private ZEDSpatialMappingManager Target public void OnEnable() { + //Bind the serialized properties to their respective properties in ZEDSpatialMappingManager. spatialMapping = (ZEDSpatialMappingManager)target; range = serializedObject.FindProperty("range_preset"); resolution = serializedObject.FindProperty("resolution_preset"); @@ -220,7 +291,7 @@ public void OnEnable() public override void OnInspectorGUI() { - bool cameraIsReady = sl.ZEDCamera.GetInstance().IsCameraReady; + bool cameraIsReady = sl.ZEDCamera.GetInstance().IsCameraReady; displayText = ZEDSpatialMapping.display ? "Hide Mesh" : "Display Mesh"; serializedObject.Update(); EditorGUILayout.BeginHorizontal(); @@ -230,14 +301,18 @@ public override void OnInspectorGUI() GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); - ZEDSpatialMapping.RESOLUTION newResolution = (ZEDSpatialMapping.RESOLUTION)EditorGUILayout.EnumPopup("Resolution", spatialMapping.resolution_preset); + GUIContent resolutionlabel = new GUIContent("Resolution", "Resolution setting for the scan. " + + "A higher resolution creates more submeshes and uses more memory, but is more accurate."); + ZEDSpatialMapping.RESOLUTION newResolution = (ZEDSpatialMapping.RESOLUTION)EditorGUILayout.EnumPopup(resolutionlabel, spatialMapping.resolution_preset); if (newResolution != spatialMapping.resolution_preset) { resolution.enumValueIndex = (int)newResolution; serializedObject.ApplyModifiedProperties(); } - ZEDSpatialMapping.RANGE newRange = (ZEDSpatialMapping.RANGE)EditorGUILayout.EnumPopup("Range", spatialMapping.range_preset); + GUIContent rangelabel = new GUIContent("Range", "Maximum distance geometry can be from the camera to be scanned. " + + "Geometry scanned from farther away will be less accurate."); + ZEDSpatialMapping.RANGE newRange = (ZEDSpatialMapping.RANGE)EditorGUILayout.EnumPopup(rangelabel, spatialMapping.range_preset); if (newRange != spatialMapping.range_preset) { range.enumValueIndex = (int)newRange; @@ -245,22 +320,26 @@ public override void OnInspectorGUI() } EditorGUILayout.BeginHorizontal(); - filterParameters.enumValueIndex = (int)(sl.FILTER)EditorGUILayout.EnumPopup("Mesh Filtering", (sl.FILTER)filterParameters.enumValueIndex); + GUIContent filteringlabel = new GUIContent("Mesh Filtering", "Whether mesh filtering is needed."); + filterParameters.enumValueIndex = (int)(sl.FILTER)EditorGUILayout.EnumPopup(filteringlabel, (sl.FILTER)filterParameters.enumValueIndex); isFilteringEnable.boolValue = true; EditorGUILayout.EndHorizontal(); - GUI.enabled = !spatialMapping.IsRunning; + GUI.enabled = !spatialMapping.IsRunning; //Don't allow changing the texturing setting while the scan is running. - isTextured.boolValue = EditorGUILayout.Toggle("Texturing", isTextured.boolValue); + GUIContent texturedlabel = new GUIContent("Texturing", "Whether surface textures will be scanned and applied. " + + "Note that texturing will add further delay to the post-scan finalizing period."); + isTextured.boolValue = EditorGUILayout.Toggle(texturedlabel, isTextured.boolValue); - GUI.enabled = cameraIsReady; + GUI.enabled = cameraIsReady; //Gray out below elements if the ZED hasn't been initialized as you can't yet start a scan. EditorGUILayout.BeginHorizontal(); if (!spatialMapping.IsRunning) { - if (GUILayout.Button("Start Spatial Mapping")) + GUIContent startmappinglabel = new GUIContent("Start Spatial Mapping", "Begin the spatial mapping process."); + if (GUILayout.Button(startmappinglabel)) { if (!ZEDSpatialMapping.display) { @@ -275,13 +354,15 @@ public override void OnInspectorGUI() { GUILayout.FlexibleSpace(); - GUILayout.Label("Spatial mapping is finishing"); + GUIContent finishinglabel = new GUIContent("Spatial mapping is finishing", "Please wait - the mesh is being processed."); + GUILayout.Label(finishinglabel); Repaint(); GUILayout.FlexibleSpace(); } else { - if (GUILayout.Button("Stop Spatial Mapping")) + GUIContent stopmappinglabel = new GUIContent("Stop Spatial Mapping", "Ends spatial mapping and begins processing the final mesh."); + if (GUILayout.Button(stopmappinglabel)) { spatialMapping.StopSpatialMapping(); } @@ -291,20 +372,25 @@ public override void OnInspectorGUI() EditorGUILayout.EndHorizontal(); GUI.enabled = cameraIsReady; + string displaytooltip = ZEDSpatialMapping.display ? "Hide the mesh from view." : "Display the hidden mesh."; + GUIContent displaylabel = new GUIContent(displayText, displaytooltip); if (GUILayout.Button(displayText)) { spatialMapping.SwitchDisplayMeshState(!ZEDSpatialMapping.display); } GUI.enabled = true; GUILayout.Label("Mesh Storage", EditorStyles.boldLabel); - saveWhenOver.boolValue = EditorGUILayout.Toggle("Save Mesh (when stop)", saveWhenOver.boolValue); + GUIContent savelabel = new GUIContent("Save Mesh (when finished)", "Whether to save the mesh and .area file when finished scanning."); + saveWhenOver.boolValue = EditorGUILayout.Toggle(savelabel, saveWhenOver.boolValue); EditorGUILayout.BeginHorizontal(); - meshPath.stringValue = EditorGUILayout.TextField("Mesh Path", meshPath.stringValue); + GUIContent pathlabel = new GUIContent("Mesh Path", "Path where the mesh is saved/loaded from. Valid file types are .obj, .ply and .bin."); + meshPath.stringValue = EditorGUILayout.TextField(pathlabel, meshPath.stringValue); - if (GUILayout.Button("...", optionsButtonBrowse)) + GUIContent findfilelabel = new GUIContent("...", "Browse for an existing .obj, .ply or .bin file."); + if (GUILayout.Button(findfilelabel, optionsButtonBrowse)) { meshPath.stringValue = EditorUtility.OpenFilePanel("Mesh file", "", "ply,obj,bin"); serializedObject.ApplyModifiedProperties(); @@ -312,11 +398,12 @@ public override void OnInspectorGUI() EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); - //GUI.enabled = cameraIsReady; + GUILayout.FlexibleSpace(); GUI.enabled = System.IO.File.Exists(meshPath.stringValue) && cameraIsReady; - if (GUILayout.Button("Load")) + GUIContent loadlabel = new GUIContent("Load", "Load an existing mesh and .area file into the scene."); + if (GUILayout.Button(loadlabel)) { spatialMapping.LoadMesh(meshPath.stringValue); } diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Fade.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Fade.cs deleted file mode 100644 index 587f0d04..00000000 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Fade.cs +++ /dev/null @@ -1,63 +0,0 @@ -//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== - -using UnityEngine; -/// -/// Fade the screen from black to the ZED image after the opening of the ZED -/// -public class LoadingFade : MonoBehaviour { - /// - /// Material used to fade - /// - private Material fader; - - /// - /// Current alpha value - /// - private float alpha; - - /// - /// start flag, set to true when the ZED is opened - /// - private bool start = false; - void Start () { - alpha = 1.5f; - fader = new Material(Resources.Load("Materials/GUI/Mat_ZED_Fade") as Material); - } - - private void OnEnable() - { - start = true; - } - - private void OnDisable() - { - start = false; - } - - private void OnRenderImage(RenderTexture source, RenderTexture destination) - { - if (start) - { - alpha -= EaseIn(0.4f, 0, 0.5f, 1.5f); - } - alpha = alpha < 0 ? 0 : alpha; - fader.SetFloat("_Alpha", alpha); - - Graphics.Blit(source, destination, fader); - if (alpha == 0) Destroy(this); - } - - /// - /// Reproduces the ease in function - /// - /// - /// - /// - /// - /// - static float EaseIn(float t, float b, float c, float d) - { - return -c * (Mathf.Sqrt(1 - (t /= d) * t) - 1) + b; - } - -} diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs index 45bfcf9d..26375a10 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs @@ -4,85 +4,99 @@ using UnityEngine.VR; /// -/// Controls the message displayed during the opening and disconnection of the ZED -/// +/// Controls the message displayed as the zed is initialized, and if it becomes disconnected. +/// Needs to be pre-attached to the ZED rig to work; not added in programmatically. +/// +/// There are separate text elements for the mono view and the stereo view to account for the +/// difference in display resolutions. 'Mono' elements are displayed in a 'Screen Space - Overlay' +/// canvas, and 'Stereo' elements in a 'Screen Space - Camera' canvas. +/// public class GUIMessage : MonoBehaviour { /// - /// Text under the loading sign for mono rig + /// Text under the loading sign for the mono rig ("Loading...", "Camera is not detected", etc.) /// private UnityEngine.UI.Text textmono; /// - /// Text under the loading sign for stereo rig's left eye + /// Text under the loading sign for stereo rig's left eye ("Loading...", "Camera is not detected", etc.) /// private UnityEngine.UI.Text textleft; /// - /// Text under the loading sign for stereo rig's right eye + /// Text under the loading sign for stereo rig's right eye ("Loading...", "Camera is not detected", etc.) /// private UnityEngine.UI.Text textright; /// - /// Event to say the ZED is ready, start the timer, to wait the textures to be initialized + /// Flag set to true when the ZED is finished initializing. + /// Starts a timer to wait for the ZED's textures to be loaded. /// private bool ready = false; /// - /// Warning container for mono rig, contains the text, background and loading sign + /// Warning container for the mono rig. Contains the text, background, and loading graphic. /// private GameObject warningmono; /// - /// Warning container for stereo rig's left eye + /// Warning container for the stereo rig's left eye. Contains the text, background, and loading graphic. /// private GameObject warningleft; /// - /// Warning container for stereo rig's right eye + /// Warning container for the stereo rig's right eye. Contains the text, background, and loading graphic. /// private GameObject warningright; /// - /// Add few time before stopping the ZED launching screen to let time to the other textures to be initialized + /// Timer used to add a 0.5 second delay between the ZED being initialized and the message disappearing. + /// This is done to let the ZED textures to finish being made. /// private float timerWarning = 0.0f; /// - /// Stop the update of the script when the flag is set to true + /// If true, stops calling most of the logic in Update() which updates the canvas elements. + /// Called once the ZED is ready and all elements have been properly disabled. /// private bool init = false; /// - /// Timer to stop the gif from rotating + /// Timer used to delay clearing the text by 0.2 seconds once the camera is initialized. /// private float timer; /// - /// Reference to the spinner for the mono rig + /// Reference to the loading spinner animation for the mono rig. /// private GameObject imagemono; /// - /// Reference to the spinner for the stereo rig's left eye + /// Reference to the loading spinner animation for the stereo rig's left eye. /// private GameObject imageleft; /// - /// Reference to the spinner for the stereo rig's right eye + /// Reference to the loading spinner animation for the stereo rig's right eye. /// private GameObject imageright; /// - /// Previous opening error + /// Opening status given during the ZED's last attempt to initialize. + /// Used to check if an error has gone on for more than one frame before changing text. /// private sl.ERROR_CODE oldInitStatus; + /// + /// Creates canvas(es) and canvas elements depending on whether the ZED rig is mono (ZED_Rig_Mono) + /// or stereo (ZED_Rig_Stereo). + /// private void Awake() { oldInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; if (!ZEDManager.IsStereoRig) //Without VR, we use a Screen Space - Overlay canvas. { + //Instantiate the mono warning prefab and set basic settings for it. warningmono = Instantiate(Resources.Load("PrefabsUI/Warning") as GameObject, transform); warningmono.SetActive(true); textmono = warningmono.GetComponentInChildren(); @@ -98,7 +112,7 @@ private void Awake() } else //In VR, we use two Screen Space - Camera canvases, one for each eye. { - //Setup the left warning prefab + //Instantiate the left warning prefab and set basic settings for it. warningleft = Instantiate(Resources.Load("PrefabsUI/Warning_VR") as GameObject, ZEDManager.Instance.GetLeftCameraTransform()); warningleft.SetActive(true); warningleft.GetComponent().worldCamera = ZEDManager.Instance.GetLeftCameraTransform().GetComponent(); @@ -108,7 +122,7 @@ private void Awake() imageleft = warningleft.transform.GetChild(0).GetChild(1).gameObject; imageleft.transform.parent.gameObject.SetActive(true); - //Setup the right warning prefab + //Instantiate the right warning prefab and set basic settings for it. warningright = Instantiate(Resources.Load("PrefabsUI/Warning_VR") as GameObject, ZEDManager.Instance.GetRightCameraTransform()); warningright.SetActive(true); warningright.GetComponent().worldCamera = ZEDManager.Instance.GetRightCameraTransform().GetComponent(); @@ -118,7 +132,7 @@ private void Awake() imageright = warningright.transform.GetChild(0).GetChild(1).gameObject; imageright.transform.parent.gameObject.SetActive(true); - if (!sl.ZEDCamera.CheckPlugin()) + if (!sl.ZEDCamera.CheckPlugin()) //Warn the use there's no SDK installed. { textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_NOT_INSTALLED); textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_NOT_INSTALLED); @@ -128,12 +142,18 @@ private void Awake() } } + /// + /// Subscribe to OnZedReady and OnZEDDisconnected events. + /// private void OnEnable() { ZEDManager.OnZEDReady += Ready; ZEDManager.OnZEDDisconnected += ZEDDisconnected; } + /// + /// Unsubscribe from OnZedReady and OnZEDDisconnected events. + /// private void OnDisable() { ZEDManager.OnZEDReady -= Ready; @@ -141,11 +161,12 @@ private void OnDisable() } /// - /// Event if ZED is disconnected + /// Re-enable canvas elements and change message when ZED is disconnected. + /// GameObjects were disabled before because the ZED had to have finished initializing before. /// void ZEDDisconnected() { - if (warningmono) + if (warningmono) //Using the mono rig. { warningmono.SetActive(true); imagemono.SetActive(true); @@ -157,7 +178,7 @@ void ZEDDisconnected() ready = false; } - if (warningleft) + if (warningleft) //Using the stereo rig. { warningleft.SetActive(true); imageleft.SetActive(true); @@ -175,16 +196,18 @@ void ZEDDisconnected() } } - // Update is called once per frame + /// + /// If visible, print the loading status of the ZED, including relevant errors. + /// void Update() { - if (!init) + if (!init) //This check will pass until 0.5 seconds after the ZED is done initializing. { sl.ERROR_CODE e = ZEDManager.LastInitStatus; - if (e == sl.ERROR_CODE.SUCCESS) + if (e == sl.ERROR_CODE.SUCCESS) //Last initialization attempt was successful. { - timer += Time.deltaTime; + timer += Time.deltaTime; //Clear text after a short delay. if (timer > 0.2f) { if (textmono) @@ -198,11 +221,12 @@ void Update() } } - if (imagemono) + + if (imagemono) //Disable mono rig canvas. { imagemono.gameObject.SetActive(false); } - else if (imageleft) + else if (imageleft) //Disable stereo rig canvases. { imageleft.gameObject.SetActive(false); imageright.gameObject.SetActive(false); @@ -210,24 +234,22 @@ void Update() } - else if (e == sl.ERROR_CODE.ERROR_CODE_LAST) + else if (e == sl.ERROR_CODE.ERROR_CODE_LAST) //"Loading..." { + //Initial error code set before an initialization attempt has returned successful or failed. + //In short, it means it's still loading. if (textmono) { textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_LOADING); - //textmono.color = Color.white; } else if (textleft) { textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_LOADING); - //textleft.color = Color.white; - textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_LOADING); - //textright.color = Color.white; } } - else if (e == sl.ERROR_CODE.CAMERA_NOT_DETECTED && oldInitStatus == sl.ERROR_CODE.CAMERA_NOT_DETECTED) + else if (e == sl.ERROR_CODE.CAMERA_NOT_DETECTED && oldInitStatus == sl.ERROR_CODE.CAMERA_NOT_DETECTED) //"Camera not detected" { if (textmono) { @@ -239,8 +261,8 @@ void Update() textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.UNABLE_TO_OPEN_CAMERA); } } - else if (e == sl.ERROR_CODE.CAMERA_DETECTION_ISSUE && oldInitStatus == sl.ERROR_CODE.CAMERA_DETECTION_ISSUE) - { + else if (e == sl.ERROR_CODE.CAMERA_DETECTION_ISSUE && oldInitStatus == sl.ERROR_CODE.CAMERA_DETECTION_ISSUE) //"Unable to open camera" + { if (textmono) { textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_DETECTION_ISSUE); @@ -251,8 +273,8 @@ void Update() textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_DETECTION_ISSUE); } } - else if (e == sl.ERROR_CODE.SENSOR_NOT_DETECTED && oldInitStatus == sl.ERROR_CODE.SENSOR_NOT_DETECTED) - { + else if (e == sl.ERROR_CODE.SENSOR_NOT_DETECTED && oldInitStatus == sl.ERROR_CODE.SENSOR_NOT_DETECTED) //"Camera motion sensor not detected" + { if (textmono) { textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SENSOR_NOT_DETECTED); @@ -263,8 +285,8 @@ void Update() textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SENSOR_NOT_DETECTED); } } - else if (e == sl.ERROR_CODE.LOW_USB_BANDWIDTH && oldInitStatus == sl.ERROR_CODE.LOW_USB_BANDWIDTH) - { + else if (e == sl.ERROR_CODE.LOW_USB_BANDWIDTH && oldInitStatus == sl.ERROR_CODE.LOW_USB_BANDWIDTH)//"Low USB bandwidth" + { if (textmono) { textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.LOW_USB_BANDWIDTH); @@ -275,6 +297,18 @@ void Update() textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.LOW_USB_BANDWIDTH); } } + else if(e == sl.ERROR_CODE.INVALID_SVO_FILE && oldInitStatus == sl.ERROR_CODE.INVALID_SVO_FILE) + { + if (textmono) + { + textmono.text = "Invalid SVO File/Path"; + } + else if (textleft) + { + textleft.text = "Invalid SVO File/Path"; + textright.text = "Invalid SVO File/Path"; + } + } else if (e==oldInitStatus) { if (textmono) @@ -289,7 +323,8 @@ void Update() } oldInitStatus = e; } - if (ready) + + if (ready) //ZED has finished initializing. Set a timer, then disable texts after it expires. { timerWarning += Time.deltaTime; if (timerWarning > 0.5f) @@ -305,8 +340,7 @@ void Update() } } - init = true; - //timerWarning = 0; + init = true; //Prevents logic above the if (ready) check from running each frame. if (imagemono) { @@ -321,6 +355,9 @@ void Update() } + /// + /// Set a flag to run timer and disable text. Called by ZEDManager.OnZEDReady when ZED finishes initializing. + /// private void Ready() { ready = true; diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs new file mode 100644 index 00000000..51ce8d38 --- /dev/null +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs @@ -0,0 +1,79 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; + +/// +/// Fades the screen from black to the ZED image when the ZED camera is first opened. +/// Added to the relevant cameras by ZEDRenderingPlane when ZED is initialized. +/// +public class LoadingFade : MonoBehaviour +{ + /// + /// Material used to perform the fade. + /// + private Material fader; + + /// + /// Current alpha value of the black overlay used to darken the image. + /// + private float alpha; + + /// + /// Start flag. Set to true when the ZED is opened. + /// + private bool start = false; + + /// + /// Sets the alpha to above 100% (to add a delay to the effect) and loads the fade material. + /// + void Start () + { + alpha = 1.5f; + fader = new Material(Resources.Load("Materials/GUI/Mat_ZED_Fade") as Material); + } + + private void OnEnable() + { + start = true; + } + + private void OnDisable() + { + start = false; + } + + /// + /// Applies the darkening effect to the camera's image. + /// Called by Unity every time the camera it's attached to renders an image. + /// + /// + /// + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (start) + { + //Lower the alpha. We use hard-coded values instead of using Time.deltaTime + //to simplify things, but the function is quite customizable. + alpha -= EaseIn(0.4f, 0, 0.5f, 1.5f); + } + alpha = alpha < 0 ? 0 : alpha; //Clamp the alpha at 0. + fader.SetFloat("_Alpha", alpha); //Apply the new alpha to the fade material. + + Graphics.Blit(source, destination, fader); //Render the image effect from the camera's output. + if (alpha == 0) Destroy(this); //Remove the component when the fade is over. + } + + /// + /// An ease-in function for reducing the alpha value each frame. + /// + /// Current time. + /// Start value. + /// Value change multiplier. + /// Duration. + /// New alpha value. + static float EaseIn(float t, float b, float c, float d) + { + return -c * (Mathf.Sqrt(1 - (t /= d) * t) - 1) + b; + } + +} diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs index 3fc42255..b216c429 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs @@ -2,10 +2,30 @@ #if UNITY_EDITOR using UnityEditor; #endif + +///This file contains classes used to add custom attributes to fields that will +///cause them to be drawn differently in the Inspector, without the need for custom editors. + +/// +/// Adds a [LabelOverride(string)] attribute that causes a public field drawn in the default +/// Inspector to have a customized label, rather than Unity generating one from the name. +/// public class LabelOverride : PropertyAttribute { + /// + /// String to override the default label with. + /// public string label; + /// + /// Tooltip to add to the label, if set. + /// public string optTooltip; + + /// + /// Constructor. Called by the [LabelOverride(string)] tag with the params inside the parenthesis. + /// + /// String to override the default label with. + /// Tooltip to add to the label, if set. public LabelOverride(string label,string tooltip="") { this.label = label; @@ -13,7 +33,11 @@ public LabelOverride(string label,string tooltip="") } #if UNITY_EDITOR - [CustomPropertyDrawer( typeof(LabelOverride) )] + /// + /// Custom property drawer for fields with a [LabelOverride(string)] attribute. + /// The label on the drawer will be set to the label value in the parameter instead of the default one. + /// + [CustomPropertyDrawer( typeof(LabelOverride) )] public class ThisPropertyDrawer : PropertyDrawer { public override void OnGUI ( Rect position , SerializedProperty property , GUIContent label ) @@ -27,10 +51,22 @@ public override void OnGUI ( Rect position , SerializedProperty property , GUICo #endif } - +/// +/// Adds a [ReadOnly(string)] attribute that will cause tagged fields to be drawn +/// with ReadOnlyDrawer in the Inspector, preventing them from being edited. +/// Used by ZEDManager to draw the status texts ("Version, Engine FPS, etc.") +/// public class ReadOnlyAttribute : PropertyAttribute { + /// + /// String to override the default label with. + /// public string label; + + /// + /// Constructor. Called by the [ReadOnly(string)] tag with parameter in the parenthesis. + /// + /// public ReadOnlyAttribute(string label) { this.label = label; @@ -38,11 +74,13 @@ public ReadOnlyAttribute(string label) } #if UNITY_EDITOR +/// +/// Custom property drawer for fields with a [ReadOnly(string)] attribute +/// that displays an uneditable text field in the Inspector. +/// [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] public class ReadOnlyDrawer : PropertyDrawer { - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs index e6f09809..4474b704 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs @@ -2,117 +2,130 @@ /// -/// Registers all the messages displayed in the Unity plugin inside an enum +/// Holds the ERROR enum returned by various high- and mid-level camera functions, and the Error2Str() method for +/// converting the errors to human-readible versions for displaying for the user. /// public class ZEDLogMessage { - - static private string zed_sdk_version = "v2.4"; - + + /// + /// Current version of the required SDK plugin as a string. Used to display errors + /// relating to a missing or mismatched SDK version. + /// + static private string zed_sdk_version + { + get + { + int major = sl.ZEDCamera.PluginVersion.Major; + int minor = sl.ZEDCamera.PluginVersion.Minor; + return "v" + major + "." + minor; + } + } + /// - /// List of the errors displayed in Unity + /// Error categories returned by various camera functions, most often in GUIMessage. + /// See ZEDCommon.ERROR_CODE for errors straignt from the SDK. /// public enum ERROR { /// - /// The screen resolution is not 16:9 + /// The screen resolution is not 16:9. /// SCREEN_RESOLUTION, /// - /// The tracking could not be initialized + /// The ZED tracking could not be initialized. /// TRACKING_NOT_INITIALIZED, /// - /// The camera has not been initialized + /// The camera failed to initialize. /// CAMERA_NOT_INITIALIZED, /// - /// The camera has not been initialized + /// The camera has not been initialized yet. /// CAMERA_LOADING, /// - /// Could not open the camera + /// Could not open the camera. /// UNABLE_TO_OPEN_CAMERA, /// - /// Camera Detection issue + /// Camera detection issue. /// CAMERA_DETECTION_ISSUE, /// - /// motion sensor not detected (ZED-M) + /// Motion sensor not detected (ZED Mini only). /// SENSOR_NOT_DETECTED, /// - /// Low USB Bandwidth + /// Low USB bandwidth. /// LOW_USB_BANDWIDTH, /// - /// CameraRig not found for the SteamVR plugin + /// SteamVR plugin Camera Rig prefab not found. /// VR_CAMERA_RIG_NOT_FOUND, /// - /// CameraRig controller not found + /// SteamVR plugin Camera Rig controller not found. /// VR_CAMERA_RIG_CONTROLLER_NOT_FOUND, /// - /// A calibration file has been found but not the SN given + /// A calibration file has been found but no controller/Tracker exists of the file's listed serial number. /// PAD_CAMERA_CALIBRATION_MISMATCH, /// - /// The serial number of the calibration tool does not match any of the current controllers + /// The serial number of the calibration tool does not match any of the current controllers. /// PAD_CAMERA_CALIBRATION_NOT_FOUND, /// - /// At least one controller must be detected + /// At least one VR controller must be detected. /// NOT_ENOUGH_PAD_DETECTED, /// - /// SteamVR is not installed. + /// SteamVR Unity plugin hasn't been imported. /// STEAMVR_NOT_INSTALLED, /// - /// SteamVR is not installed. + /// Oculus Integration Unity plugin hasn't been imported. /// OVR_NOT_INSTALLED, /// - /// The ZED is disconnected + /// The ZED has been disconnected. (It was connected previously) /// ZED_IS_DISCONNECETD, /// - /// The SDK is not installed or a dependency is missing + /// The ZED SDK is not installed or a dependency is missing. /// SDK_NOT_INSTALLED, /// - /// The SDK is not installed or a dependency is missing + /// The ZED SDK is installed but it's not the version the Unity plugin requires. /// INCORRECT_ZED_SDK_VERSION, /// - /// The SDK has a missing dependency + /// The SDK has a missing dependency. /// SDK_DEPENDENCIES_ISSUE, /// - /// The Mesh is too small to accept a naVMesh + /// Scanned mesh is too small to create a Nav Mesh. /// NAVMESH_NOT_GENERATED, /// - /// The tracking could not load the spatial memory area + /// The tracking system could not load the spatial memory area file. /// TRACKING_BASE_AREA_NOT_FOUND, - } /// - /// Converts an enum to a string + /// Converts an ERROR enum to a string for displaying to the user. Called by various editor windows. /// - /// + /// Error type to be converted to a string. /// static public string Error2Str(ERROR error) { switch (error) { case ERROR.SCREEN_RESOLUTION: - return "Warning: screen size must respect 16:9 aspect ratio"; + return "Warning: Screen size should be set to 16:9 aspect ratio"; case ERROR.TRACKING_NOT_INITIALIZED: return "Error: Unable to initialize Tracking module"; @@ -136,39 +149,42 @@ static public string Error2Str(ERROR error) return "Loading..."; case ERROR.VR_CAMERA_RIG_NOT_FOUND: - return "Warning: No VR CameraRig object found. Make sure you attach the CameraRig SteamVR Prefab in the project to be able to use a VR controller.\n Otherwise, make sure the tracking is activated in the ZED Manager interface"; + return "Warning: No SteamVR [Camera Rig] object found. Make sure you attach the CameraRig SteamVR Prefab in the project to be able to use a VR controller.\n " + + "Otherwise, make sure the tracking is activated in the ZED Manager interface"; case ERROR.VR_CAMERA_RIG_CONTROLLER_NOT_FOUND: - return "Warning: One controller is recommended for the external camera"; + return "Warning: At least one controller is recommended for the external camera"; case ERROR.PAD_CAMERA_CALIBRATION_MISMATCH: - return "Warning: VR Controller and ZED Camera must be calibrated before use (by using the GreenScreen Calibration tool). \n It seems that the current controller has not been calibrated."; + return "Warning: VR Controller and ZED Camera must be calibrated before use with Stereolabs' GreenScreen Calibration tool). " + + "\n The controller/Tracker in the calibration file is not present."; case ERROR.PAD_CAMERA_CALIBRATION_NOT_FOUND: - return "Warning: VR Controller and ZED Camera must be calibrated before use (by using the GreenScreen Calibration tool). \n It seems that no calibration has been made"; + return "Warning: VR Controller and ZED Camera must be calibrated before use with Stereolabs' GreenScreen Calibration tool). " + + "\n No calibration file has been detected."; case ERROR.NOT_ENOUGH_PAD_DETECTED: - return "Warning : At least one controller must be detected. Number of devices detected: "; + return "Warning: At least one controller must be detected. Number of devices detected: "; case ERROR.STEAMVR_NOT_INSTALLED: - return "Warning : SteamVR is not installed."; + return "Warning: SteamVR is not installed."; case ERROR.OVR_NOT_INSTALLED: - return "Warning : OVR Plugin is not installed."; + return "Warning: OVR Plugin is not installed."; case ERROR.ZED_IS_DISCONNECETD: - return "Camera is not detected"; + return "Camera disconnected"; case ERROR.SDK_NOT_INSTALLED: - return "The SDK is not installed"; + return "ZED SDK not installed"; case ERROR.SDK_DEPENDENCIES_ISSUE: - return "The ZED plugin cannot be loaded. \n Please check that you have the latest ZED SDK "+ zed_sdk_version +" installed" + + return "The ZED plugin cannot be loaded. \n Please check that you have ZED SDK "+ zed_sdk_version +" installed" + "\n\n If the problem persists, please contact our support team at support@stereolabs.com\n"; case ERROR.NAVMESH_NOT_GENERATED: - return "The NavMesh cannot be generated, please change the settings of the agent, or scan a wider zone."; + return "The NavMesh cannot be generated. Please change the settings of the Navigation Agent, or scan a wider zone."; case ERROR.TRACKING_BASE_AREA_NOT_FOUND: - return "The tracking could not load the spatial memory area"; + return "The tracking could not load the spatial memory area file."; default: diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs index 2c34abeb..e09b563e 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs @@ -6,72 +6,91 @@ using UnityEditor; #endif /// -/// Manages the SVO, only used as an interface for Unity -/// +/// Lets you play back a recorded SVO file, which works in place of the input from a real ZED, +/// or record an SVO file from a live ZED. +/// To use, attach to the same GameObject as ZED Manager (ZED_Rig_Mono or ZED_Rig_Stereo). +/// When playing an SVO, the SDK behaves the same as if a real ZED were attached, so all regular features +/// are available. The one exception is pass-through AR, as the ZED's timestamps and transform will both be +/// significantly out of sync with the VR headset. +/// public class ZEDSVOManager : MonoBehaviour { /// - /// Set to true to record a SVO + /// Set to true to record an SVO. Recording begins when the ZED initialized and ends when the + /// application finishes. /// [SerializeField] + [Tooltip("Set to true to record an SVO. Recording begins when the ZED initialized and ends when " + + "the application finishes.")] public bool record = false; /// - /// Set to true to read a SVO, a SVO cannot be read and written at once + /// Set to true to read an SVO, using it as input instead of a real ZED. An SVO cannot be read and recorded + /// at the same time. /// [SerializeField] + [Tooltip("Set to true to read an SVO, using it as input instead of a real ZED. " + + "An SVO cannot be read and recorded at the same time.")] public bool read = false; /// - /// Set the video file to record or read + /// Path to the SVO to be read, or where a new SVO will be recorded. + /// Note: If building the application, put the file in the root directory or specify a non-relative path + /// to preserve this reference. /// [SerializeField] [HideInInspector] public string videoFile = "Assets/ZEDRecording.svo"; /// - /// Loop the svo, if read is set to true + /// If reading an SVO, set this to true if the SVO should repeat once it finishes. + /// Some features won't handle this gracefully, such as tracking. /// [SerializeField] - [Tooltip("Loop the SVO")] + [Tooltip("If reading an SVO, set this to true if the SVO should repeat once it finishes. " + + "Some features won't handle this gracefully, such as tracking.")] public bool loop = false; + /// + /// If reading an SVO, set true to use frame timestamps to set playback speed. Dropped + /// frames will cause a 'pause' in playback instead of a 'skip.' + /// + [Tooltip("If reading an SVO, set true to use frame timestamps to set playback speed. " + + "Dropped frames will cause a 'pause' in playback instead of a 'skip.'")] [SerializeField] [HideInInspector] public bool realtimePlayback = true; /// - /// Current frame of the SVO (read) + /// Current frame being read from the SVO. Doesn't apply when recording. /// [HideInInspector] [SerializeField] private int currentFrame = 0; - /// - /// Number max of frames in the SVO + /// Current frame being read from the SVO. Doesn't apply when recording. /// - [HideInInspector] - [SerializeField] - private int numberFrameMax = 0; + public int CurrentFrame + { + get + { + return currentFrame; + } + set + { + currentFrame = value; + } + } /// - /// Pause the SVO, Unity will continue to run + /// Total number of frames in a loaded SVO. /// [HideInInspector] [SerializeField] - public bool pause = false; - - - - - /// - /// Compression mode to register a SVO - /// - [SerializeField] - public sl.SVO_COMPRESSION_MODE compressionMode = sl.SVO_COMPRESSION_MODE.LOSSY_BASED; - + private int numberFrameMax = 0; /// - /// Number frame max of the SVO + /// Total number of frames in a loaded SVO. /// public int NumberFrameMax { @@ -86,48 +105,45 @@ public int NumberFrameMax } /// - /// Current frame of the SVO (number) + /// Set true to pause the SVO reading or recording. Will not pause the Unity scene itself. /// - public int CurrentFrame - { - get - { - return currentFrame; - } - set - { - currentFrame = value; - } - } - - - private bool need_NewFrame; - public bool NeedNewFrameGrab - { + [HideInInspector] + [SerializeField] + public bool pause = false; - get - { - return need_NewFrame; - } - set - { - need_NewFrame = value; - } + /// + /// Compression mode used when recording an SVO. + /// Uncompressed SVOs are extremely large (multiple gigabytes per minute). + /// + [Tooltip("Compression mode used when recording an SVO. " + + "Uncompressed SVOs are extremely large (multiple gigabytes per minute).")] + [SerializeField] + public sl.SVO_COMPRESSION_MODE compressionMode = sl.SVO_COMPRESSION_MODE.LOSSY_BASED; - } + /// + /// Flag set to true when we need to force ZEDManager to grab a new frame, even though + /// SVO playback is paused. Used when the SVO is paused but the playback slider has moved. + /// + public bool NeedNewFrameGrab { get; set; } /// - /// Init the SVOManager + /// Changes the value of record if recording fails, and gets the length of a read SVO file. /// - /// + /// Reference to the Scene's ZEDCamera instance. public void InitSVO(sl.ZEDCamera zedCamera) { if (record) { - if (zedCamera.EnableRecording(videoFile,compressionMode) != sl.ERROR_CODE.SUCCESS) + sl.ERROR_CODE svoerror = zedCamera.EnableRecording(videoFile, compressionMode); + if (svoerror != sl.ERROR_CODE.SUCCESS) { record = false; } + else if(svoerror == sl.ERROR_CODE.SVO_RECORDING_ERROR) + { + Debug.LogError("SVO recording failed. Check that there is enough space on the drive and that the " + + "path provided is valid."); + } } if (read) @@ -139,13 +155,18 @@ record = false; #if UNITY_EDITOR - +/// +/// Custom editor for ZEDSVOManager to change how it's drawn in the Inspector. +/// Adds a playback slider and pause button, and makes Record and Read mutually-exclusive. +/// [CustomEditor(typeof(ZEDSVOManager)), CanEditMultipleObjects] public class SVOManagerInspector : Editor { + //Caches for record and read values, to make them mutually exclusive. private bool current_recordValue = false; private bool current_readValue = false; + //Serializable versions of ZEDSVOManager's values so changes can be saved/serialized. private SerializedProperty pause; private SerializedProperty record; private SerializedProperty read; @@ -154,13 +175,18 @@ public class SVOManagerInspector : Editor private SerializedProperty currentFrame; private SerializedProperty numberFrameMax; - Rect drop_area; + Rect drop_area; //Bounds for dragging and dropping SVO files. - private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) }; + private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) }; //Adds padding for the SVO browse button. string pauseText = "Pause"; + string pauseTooltip = " SVO playback or recording."; //Appended to the pause Text to make tooltip text. - string[] filters = { "Svo files", "svo" }; + string[] filters = { "Svo files", "svo" }; //Filters used for browsing for an SVO. private ZEDSVOManager obj; + + /// + /// Called by Unity each time the editor is viewed. + /// public override void OnInspectorGUI() { serializedObject.Update(); @@ -170,13 +196,19 @@ public override void OnInspectorGUI() using (new EditorGUI.DisabledScope(Application.isPlaying)) { - string tooltip = "Uses timecodes of each frame for playback. Causes a pause for dropped frames or when pause was used during recording."; + string tooltip = "If reading an SVO, set true to use frame timestamps to set playback speed." + + "Dropped frames will cause a 'pause' in playback instead of a 'skip.'"; obj.realtimePlayback = EditorGUILayout.Toggle(new GUIContent("Realtime Playback", tooltip), obj.realtimePlayback); } - EditorGUILayout.BeginHorizontal(); - videoFile.stringValue = EditorGUILayout.TextField("SVO Path", videoFile.stringValue); - if (GUILayout.Button("...", optionsButtonBrowse)) + EditorGUILayout.BeginHorizontal(); + GUIContent pathlabel = new GUIContent("SVO Path", "Path to the SVO to be read, or where a new SVO will be recorded. " + + "Note: If building the application, put the file in the root directory or specify a non-relative path " + + "to preserve this reference."); + videoFile.stringValue = EditorGUILayout.TextField(pathlabel, videoFile.stringValue); + + GUIContent loadlabel = new GUIContent("...", "Browse for existing SVO file."); + if (GUILayout.Button(loadlabel, optionsButtonBrowse)) { obj.videoFile = EditorUtility.OpenFilePanelWithFilters("Load SVO", "", filters); serializedObject.ApplyModifiedProperties(); @@ -193,12 +225,13 @@ public override void OnInspectorGUI() EditorGUI.BeginChangeCheck(); GUI.enabled = (obj.NumberFrameMax > 0); - currentFrame.intValue = EditorGUILayout.IntSlider("Frame ", currentFrame.intValue, 0, numberFrameMax.intValue); + GUIContent sliderlabel = new GUIContent("Frame ", "SVO playback position"); + currentFrame.intValue = EditorGUILayout.IntSlider(sliderlabel, currentFrame.intValue, 0, numberFrameMax.intValue); if (EditorGUI.EndChangeCheck()) { if (sl.ZEDCamera.GetInstance() != null) { - //If the slider of frame from the SVO has moved, grab mannually the frame and update the textures + //If the slider of frame from the SVO has moved, manually grab the frame and update the textures. sl.ZEDCamera.GetInstance().SetSVOPosition(currentFrame.intValue); if (pause.boolValue) { @@ -210,17 +243,21 @@ public override void OnInspectorGUI() GUI.enabled = sl.ZEDCamera.GetInstance() != null && sl.ZEDCamera.GetInstance().IsCameraReady; pauseText = pause.boolValue ? "Resume" : "Pause"; - if (GUILayout.Button(pauseText)) + GUIContent pauselabel = new GUIContent(pauseText, pauseText + pauseTooltip); + if (GUILayout.Button(pauselabel)) { pause.boolValue = !pause.boolValue; } GUI.enabled = true; DropAreaGUI(); - serializedObject.ApplyModifiedProperties(); + serializedObject.ApplyModifiedProperties(); //Applies changes to serialized properties to the values they represent. } + /// + /// Binds the serialized properties to their respective values in ZEDSVOManager. + /// private void OnEnable() { pause = serializedObject.FindProperty("pause"); @@ -234,8 +271,8 @@ record = serializedObject.FindProperty("record"); } /// - /// To allow looping when reading is on - /// To not allow to read and record at the same time + /// Allows looping when reading an SVO file (only) and prevents + /// reading and recording from both being true at the same time. /// private void CheckChange() { @@ -263,9 +300,8 @@ private void CheckChange() } - /// - /// Helper to get the name of a drag and dropped file + /// Helper to get the name of a drag and dropped file. /// public void DropAreaGUI() { @@ -290,6 +326,4 @@ public void DropAreaGUI() } } } - - #endif diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs index d728e229..baf1809b 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs @@ -1,34 +1,45 @@ using UnityEngine; + /// -/// Functions support to help to retrieve depth and normals -/// +/// Holds numerous static functions for getting info about the real world in +/// specific places, to compare to the virtual world in the same place. +/// Examples include knowing where a real-world point you click on is in Unity world space, +/// knowing what direction a real-world surface is facing, checking for collisions with the real world. +/// +/// Functions that take a Vector2 for screen space (usually named "pixel" or something similar) are great for +/// when you want to click on the screen to test the real-world 'thing' you click on. To do this, use Input.mousePosition +/// and make a Vector2 out of the X and Y of the Vector3 it returns. +/// Most functions take a Camera as a parameter. Use the one providing the image on the screen - +/// usually the left camera in the ZED rig, which can be easily retrieved using ZEDManager.GetLeftCameraTransform(). +/// public class ZEDSupportFunctions { - /*********************************************************************************************** + /*********************************************************************************************** ******************** BASIC "GET" FUNCTIONS **************************** ***********************************************************************************************/ /// - /// Get the Normal vector at a given pixel (i,j). the Normal can be given regarding camera reference or in the world reference. + /// Gets the normal vector (the direction a surface is pointing) at a given screen-space pixel (i,j). + /// The normal can be given relative to the camera or the world. Returns false if outside camera's view frustum. /// - /// position of the pixel - /// Reference frame given by the enum sl.REFERENCE_FRAME - /// Unity Camera (to access world to camera transform - /// normal that will be filled - /// true if success, false otherwie - public static bool GetNormalAtPixel(Vector2 pixel, sl.REFERENCE_FRAME reference_frame,Camera cam, out Vector3 normal) + /// Pixel coordinates. + /// Reference frame given by the enum sl.REFERENCE_FRAME. + /// Unity Camera used for world-camera space conversion. + /// Normal to be filled. + /// True if successful, false otherwise. + public static bool GetNormalAtPixel(Vector2 pixel, sl.REFERENCE_FRAME reference_frame, Camera cam, out Vector3 normal) { Vector4 n; bool r = sl.ZEDCamera.GetInstance().GetNormalValue(new Vector3(pixel.x,pixel.y, 0), out n); switch (reference_frame) { - case sl.REFERENCE_FRAME.CAMERA: + case sl.REFERENCE_FRAME.CAMERA: //Relative to the provided camera. normal = n; break; - case sl.REFERENCE_FRAME.WORLD: + case sl.REFERENCE_FRAME.WORLD: //Relative to the world. normal = cam.transform.TransformDirection(n); break; default : @@ -39,15 +50,16 @@ public static bool GetNormalAtPixel(Vector2 pixel, sl.REFERENCE_FRAME reference_ return r; } - /// - /// Get the Normal vector at a world position (x,y,z). the Normal can be given regarding camera reference or in the world reference. - /// - /// world position - /// Reference frame given by the enum sl.REFERENCE_FRAME - /// Unity Camera (to access world to camera transform - /// normal vector that will be filled - /// true if success, false otherwie - public static bool GetNormalAtWorldLocation(Vector3 position, sl.REFERENCE_FRAME reference_frame,Camera cam, out Vector3 normal) + /// + /// Gets the normal vector (the direction a surface is pointing) at a world position (x,y,z). + /// The normal can be given relative to the camera or the world. + /// + /// World position. + /// Reference frame given by the enum sl.REFERENCE_FRAME. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Normal vector to be filled. + /// True if successful, false otherwise. + public static bool GetNormalAtWorldLocation(Vector3 position, sl.REFERENCE_FRAME reference_frame,Camera cam, out Vector3 normal) { Vector4 n; bool r = sl.ZEDCamera.GetInstance().GetNormalValue(cam.WorldToScreenPoint(position), out n); @@ -71,9 +83,14 @@ public static bool GetNormalAtWorldLocation(Vector3 position, sl.REFERENCE_FRAME } /// - /// Get forward distance (ie depth) value at a given image pixel - /// - /// + /// Gets forward distance (i.e. depth) value at a given image pixel. + /// + /// Forward distance/depth is distinct from Euclidean distance in that it only measures + /// distance on the Z axis; the pixel's left/right or up/down position relative to the camera + /// makes no difference to the depth value. + /// + /// Pixel coordinates in screen space. + /// Forward distance/depth to given pixel. /// public static bool GetForwardDistanceAtPixel(Vector2 pixel, out float depth) { @@ -84,15 +101,18 @@ public static bool GetForwardDistanceAtPixel(Vector2 pixel, out float depth) return true; } - - /// - /// Get forward distance (ie depth) at a world position (x,y,z). - /// - /// (x,y,z) world location - /// Camera object - /// Depth value in float - /// - public static bool GetForwardDistanceAtWorldLocation(Vector3 position, Camera cam,out float depth) + /// + /// Gets forward distance (i.e. depth) at a given world position (x,y,z). + /// + /// Forward distance/depth is distinct from Euclidean distance in that it only measures + /// distance on the Z axis; the pixel's left/right or up/down position relative to the camera + /// makes no difference to the depth value. + /// + /// World position to measure. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Forward distance/depth to given position. + /// + public static bool GetForwardDistanceAtWorldLocation(Vector3 position, Camera cam, out float depth) { Vector3 pixelPosition = cam.WorldToScreenPoint (position); @@ -105,12 +125,16 @@ public static bool GetForwardDistanceAtWorldLocation(Vector3 position, Camera ca - /// - /// Get euclidean distance value at a given image pixel to the left camera - /// - /// - /// - public static bool GetEuclideanDistanceAtPixel(Vector2 pixel, out float distance) + /// + /// Gets the Euclidean distance from the world position of a given image pixel. + /// + /// Euclidean distance is distinct from forward distance/depth in that it takes into account the point's X and Y position + /// relative to the camera. It's the actual distance between the camera and the point in world space. + /// + /// Pixel coordinates in screen space. + /// Euclidean distance to given pixel. + /// + public static bool GetEuclideanDistanceAtPixel(Vector2 pixel, out float distance) { float d = sl.ZEDCamera.GetInstance().GetDistanceValue(new Vector3(pixel.x, pixel.y, 0)); distance = d; @@ -120,14 +144,17 @@ public static bool GetEuclideanDistanceAtPixel(Vector2 pixel, out float distance } - /// - /// Get the euclidean distance value from a point at a world position (x,y,z) to the left camera - /// - /// (x,y,z) world location - /// Camera object - /// Depth value in float - /// - public static bool GetEuclideanDistanceAtWorldLocation(Vector3 position, Camera cam,out float distance) + /// + /// Gets the Euclidean distance from the given caera to a point in the world (x,y,z). + /// + /// Euclidean distance is distinct from forward distance/depth in that it takes into account the point's X and Y position + /// relative to the camera. It's the actual distance between the camera and the point in world space. + /// + /// World position to measure. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Euclidean distance to given position. + /// + public static bool GetEuclideanDistanceAtWorldLocation(Vector3 position, Camera cam, out float distance) { Vector3 pixelPosition = cam.WorldToScreenPoint (position); @@ -138,34 +165,35 @@ public static bool GetEuclideanDistanceAtWorldLocation(Vector3 position, Camera return true; } /// - /// Get the world position of the given image pixel. + /// Gets the world position of the given image pixel. /// - /// - /// - /// true if success, false otherwise + /// Pixel coordinates in screen space. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Filled with the world position of the specified pixel. + /// True if it found a value, false otherwise (such as if it's outside the camera's view frustum) public static bool GetWorldPositionAtPixel(Vector2 pixel, Camera cam, out Vector3 worldPos) { float d; worldPos = Vector3.zero; if (!GetForwardDistanceAtPixel(pixel, out d)) return false; - //convert regarding screen size + //Adjust for difference between screen size and ZED's image resolution. float xp = pixel.x * sl.ZEDCamera.GetInstance().ImageWidth / Screen.width; float yp = pixel.y * sl.ZEDCamera.GetInstance().ImageHeight / Screen.height; - //Extract world position using S2W + + //Extract world position using screen-to-world transform. worldPos = cam.ScreenToWorldPoint(new Vector3(xp, yp,d)); return true; } /// - /// Checks if a world location is visible from the camera (true) or masked by a virtual object (with collider) - /// This uses the raycast to check if we hit something or not + /// Checks if a real-world location is visible from the camera (true) or masked by a virtual object (with a collider). /// - /// This only occurs with the virtual objects that have a collider - /// (x,y,z) world location - /// - /// + /// The virtual object must have a collider for this to work as it uses a collision test. + /// Position to check in world space. Must be in camera's view to check against the real world. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// True if visible, false if obscurred. public static bool IsLocationVisible(Vector3 position, Camera cam) { RaycastHit hit; @@ -178,16 +206,14 @@ public static bool IsLocationVisible(Vector3 position, Camera cam) return true; } - - /// - /// Checks if an image pixel is visible from the camera (true) or masked by a virtual object (with collider) - /// This uses the raycast to check if we hit something or not - /// - /// This only occurs with the virtual objects that have a collider - /// - /// - /// - public static bool IsPixelVisible(Vector2 pixel, Camera cam) + /// + /// Checks if the real world at an image pixel is visible from the camera (true) or masked by a virtual object (with a collider). + /// + /// The virtual object must have a collider for this to work as it uses a collision test. + /// Screen space coordinates of the real-world pixel. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// True if visible, false if obscurred. + public static bool IsPixelVisible(Vector2 pixel, Camera cam) { RaycastHit hit; float d; @@ -202,37 +228,44 @@ public static bool IsPixelVisible(Vector2 pixel, Camera cam) - /*********************************************************************************************** + /*********************************************************************************************** ******************** HIT TEST FUNCTIONS ****************************** ***********************************************************************************************/ - /// - /// Static functions for checking collisions or 'hit' with the real world. - /// In each function, "countinvalidascollision" specifies if off-screen pixels or missing depth values should count as collision. - /// "realworldthickness" specifies how far back a point needs to be behind the real world before it's not considered a collision. - /// + /// + /// Static functions for checking collisions or 'hits' with the real world. This does not require + /// scanning/spatial mapping or plane detection as it used the live depth map. + /// Each is based on the premise that if a point is behind the real world, it has intersected with it (except when + /// using realworldthickness). This is especially when checked each frame on a moving object, like a projectile. + /// In each function, "countinvalidascollision" specifies if off-screen pixels or missing depth values should count as collisions. + /// "realworldthickness" specifies how far back a point needs to be behind the real world before it's not considered a collision. + /// - /// - /// Checks an individual point in world space to see if it's occluded by the real world. - /// - /// 3D point in the world that belongs to a virtual object - /// camera (usually left camera) - /// True if the test represents a valid hit test. - public static bool HitTestAtPoint(Camera camera, Vector3 point, bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) + /// + /// Checks an individual point in world space to see if it's occluded by the real world. + /// + /// Unity Camera used for world-camera space conversion (usually left camera). + /// 3D point in the world that belongs to a virtual object. + /// Whether a collision that can't be tested (such as when it's off-screen) + /// is counted as hitting something. + /// Sets the assumed thickness of the real world. Points further away than the world by + /// more than this amount won't return true, considered "behind" the real world instead of inside it. + /// True if the test represents a valid hit test. + public static bool HitTestAtPoint(Camera camera, Vector3 point, bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) { - //Transform the point into screen space + //Transform the point into screen space. Vector3 screenpoint = camera.WorldToScreenPoint(point); - //Make sure it's within our view frustrum (except for clipping planes) + //Make sure it's within our view frustrum (excluding clipping planes). if (!CheckScreenView (point, camera)) { return countinvalidascollision; } - //Compare distance in _virtual camera to corresponding point in distance map. + //Compare distance in virtual camera to corresponding point in distance map. float realdistance; - ZEDSupportFunctions.GetEuclideanDistanceAtPixel(new Vector2(screenpoint.x, screenpoint.y), out realdistance); + GetEuclideanDistanceAtPixel(new Vector2(screenpoint.x, screenpoint.y), out realdistance); //If we pass bad parameters, or we don't have an accurate reading on the depth, we can't test. if(realdistance <= 0f) @@ -240,29 +273,33 @@ public static bool HitTestAtPoint(Camera camera, Vector3 point, bool countinvali return countinvalidascollision; //We can't read the depth from that pixel. } - ///Detection is the space if (realdistance <= Vector3.Distance(point, camera.transform.position) && Vector3.Distance(point, camera.transform.position) - realdistance <= realworldthickness) { - return true; //The real pixel is closer or at the same depth as the virtual point. That's a collision. + return true; //The real pixel is closer or at the same depth as the virtual point. That's a collision (unless closer by more than realworldthickness). } - else return false; //It's behind the virtual point. + else return false; //The real pixel is behind the virtual point. } - /// - /// Performs a "raycast" by checking for collisions/hit in a series of points on a ray. - /// - /// camera (left camera usually) - /// starting position of the ray - /// rotation of the ray from starting point - /// maximum distance of the ray - /// distance between sample dots that define the ray - /// out : collision point - /// - public static bool HitTestOnRay(Camera camera, Vector3 startpos, Quaternion rot, float maxdistance, float distbetweendots, out Vector3 collisionpoint, + /// + /// Performs a "raycast" by checking for collisions/hit in a series of points on a ray. + /// Calls HitTestAtPoint at each point on the ray, spaced apart by distbetweendots. + /// + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Starting position of the ray + /// Direction of the ray. + /// Maximum distance of the ray + /// Distance between sample dots. 1cm (0.01f) is recommended for most casses, but + /// increase to improve performance at the cost of accuracy. + /// Fills the point where the collision occurred, if any. + /// Whether a collision that can't be tested (such as when it's off-screen) + /// is counted as hitting something. + /// Sets the assumed thickness of the real world. Points further away than the world by + /// more than this amount won't return true, considered "behind" the real world instead of inside it. + /// + public static bool HitTestOnRay(Camera camera, Vector3 startpos, Quaternion rot, float maxdistance, float distbetweendots, out Vector3 collisionpoint, bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) { - //We're gonna check for occlusion in a series of dots, spaced apart evenly. - + //Check for occlusion in a series of dots, spaced apart evenly. Vector3 lastvalidpoint = startpos; for (float i = 0; i < maxdistance; i += distbetweendots) { @@ -283,30 +320,37 @@ public static bool HitTestOnRay(Camera camera, Vector3 startpos, Quaternion rot, } } - //This code will only be reached if there's no collision + //There was no collision at any of the points checked. collisionpoint = lastvalidpoint; return false; } - /// - /// Checks if a spherical area is blocked above a given percentage. Useful for checking is a drone spawn point is valid. - /// Works by checking random points around the sphere for occlusion, Monte Carlo-style, so more samples means greater accuracy. - /// - /// camera (Left camera usually) - /// Center point of the sphere that belongs to the virtual objects - /// radius of the sphere - /// number of dots in the sphere (increasing this number will increase the processing time) - /// percentage between 0 and 1 that defines a collision (if greater than) - /// - public static bool HitTestOnSphere(Camera camera, Vector3 centerpoint, float radius, int numberofsamples, float blockedpercentagethreshold, + /// + /// Checks if a spherical area is blocked above a given percentage. Useful for checking if a drone spawn point is valid. + /// Works by checking random points around the sphere for occlusion, Monte Carlo-style, so more samples means greater accuracy. + /// + /// Unlike HitTestOnRay, you can allow some individual points to collide without calling the whole thing a collision. This is useful + /// to account for noise, or to allow objects to "graze" the real world. Adjust this with blockedpercentagethreshold. + /// See the Drone or DroneSpawner class for examples. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Center point of the sphere. + /// Radius of the sphere + /// Number of dots in the sphere. Increase to improve accuracy at the cost of performance. + /// Percentage (0 - 1) that the number of hits must exceed for a collision. + /// Whether a collision that can't be tested (such as when it's off-screen) + /// is counted as hitting something. + /// Sets the assumed thickness of the real world. Points further away than the world by + /// more than this amount won't return true, considered "behind" the real world instead of inside it. + /// Whether the sphere is colliding with the real world. + public static bool HitTestOnSphere(Camera camera, Vector3 centerpoint, float radius, int numberofsamples, float blockedpercentagethreshold = 0.2f, bool countinvalidascollision = true, float realworldthickness = Mathf.Infinity) { int occludedpoints = 0; for (int i = 0; i < numberofsamples; i++) { - //Find a random point along the bounds of a sphere and check if it's occluded + //Find a random point along the bounds of a sphere and check if it's occluded. Vector3 randompoint = Random.onUnitSphere * radius + centerpoint; if(HitTestAtPoint(camera, randompoint, countinvalidascollision, realworldthickness)) { @@ -314,31 +358,40 @@ public static bool HitTestOnSphere(Camera camera, Vector3 centerpoint, float rad } } - //See if the percentage of occluded pixels exceeds the threshold + //See if the percentage of occluded pixels exceeds the threshold. float occludedpercent = occludedpoints / (float)numberofsamples; if (occludedpercent > blockedpercentagethreshold) { - return true; //Occluded + return true; //Occluded. } else return false; } - /// - /// Checks for collisions with the vertices of a given mesh with a given transform. - /// Expensive, and quality depends on density and distribution of the mesh's vertices. - /// - /// camera (Left camera usually) - /// Mesh object - /// world transform - /// percentage between 0 and 1 that defines a collision (if greater than) - /// percentage between 0 and 1 that samples the mesh (will skip vertices if less than 1) - /// see HitTestAtPoint - /// see HitTestAtPoint - /// - public static bool HitTestOnMeshVertices(Camera camera, Mesh mesh, Transform worldtransform, float blockedpercentagethreshold, float meshsamplepercent = 1, + /// + /// Checks for collisions at each vertex of a given mesh with a given transform. + /// Expensive on large meshes, and quality depends on density and distribution of the mesh's vertices. + /// + /// As a mesh's vertices are not typically designed to be tested in this way, it is almost always better + /// to use a sphere or a raycast; areas inside large faces of the mesh won't register as colliding, and + /// dense parts of the mesh will do more checks than is necessary. To make proper use of this feature, make a + /// custom mesh with vertices spaced evenly, and use that in place of the mesh being used for rendering. + /// + /// Unity Camera used for world-camera space conversion (usually left camera) + /// Mesh to supply the vertices. + /// World position, rotation and scale of the mesh. + /// Percentage (0 - 1) that the number of hits must exceed for a collision. + /// Percentage of the mesh's vertices to check for hits. Lower to improve performance + /// at the cost of accuracy. + /// Whether a collision that can't be tested (such as when it's off-screen) + /// is counted as hitting something. + /// Sets the assumed thickness of the real world. Points further away than the world by + /// more than this amount won't return true, considered "behind" the real world instead of inside it. + /// True if the mesh collided with the real world. + public static bool HitTestOnMesh(Camera camera, Mesh mesh, Transform worldtransform, float blockedpercentagethreshold, float meshsamplepercent = 1, bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) { - //Find how often we check samples, represented as an integer denominator + //Find how often we check samples, represented as an integer denominator. + //For example, if meshamplepercent is 0.2, then we'll check every five vertices. int checkfrequency = Mathf.RoundToInt(1f / Mathf.Clamp01(meshsamplepercent)); int totalchecks = Mathf.FloorToInt(mesh.vertices.Length / (float)checkfrequency); @@ -362,31 +415,40 @@ public static bool HitTestOnMeshVertices(Camera camera, Mesh mesh, Transform wor return false; } - /// - /// Checks for collisions with the vertices of the mesh in a meshfilter. - /// Expensive, and quality depends on density and distribution of the mesh's vertices. - /// - /// camera (Left camera usually) - /// Mesh filter object - /// percentage between 0 and 1 that defines a collision (if greater than) - /// percentage between 0 and 1 that samples the mesh (will skip vertices if less than 1) - /// see HitTestAtPoint - /// see HitTestAtPoint - /// - public static bool HitTestOnMeshFilter(Camera camera, MeshFilter meshfilter, float blockedpercentagethreshold, float meshsamplepercent = 1, + /// + /// Checks for collisions at each vertex of a given mesh with a given transform. + /// Expensive on large meshes, and quality depends on density and distribution of the mesh's vertices. + /// + /// As a mesh's vertices are not typically designed to be tested in this way, it is almost always better + /// to use a sphere or a raycast; areas inside large faces of the mesh won't register as colliding, and + /// dense parts of the mesh will do more checks than is necessary. To make proper use of this feature, make a + /// custom mesh with vertices spaced evenly, and use that in place of the mesh being used for rendering. + /// + /// Unity Camera used for world-camera space conversion (usually left camera) + /// MeshFilter whose mesh value will supply the vertices. + /// World position, rotation and scale of the mesh. + /// Percentage (0 - 1) that the number of hits must exceed for a collision. + /// Percentage of the mesh's vertices to check for hits. Lower to improve performance + /// at the cost of accuracy. + /// Whether a collision that can't be tested (such as when it's off-screen) + /// is counted as hitting something. + /// Sets the assumed thickness of the real world. Points further away than the world by + /// more than this amount won't return true, considered "behind" the real world instead of inside it. + /// True if the mesh collided with the real world. + public static bool HitTestOnMesh(Camera camera, MeshFilter meshfilter, float blockedpercentagethreshold, float meshsamplepercent = 1, bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) { - return HitTestOnMeshVertices(camera, meshfilter.mesh, meshfilter.transform, blockedpercentagethreshold, meshsamplepercent, countinvalidascollision, realworldthickness); + return HitTestOnMesh(camera, meshfilter.mesh, meshfilter.transform, blockedpercentagethreshold, meshsamplepercent, countinvalidascollision, realworldthickness); } - - /// - /// Simply checking if the object is within our view frustrum. - /// - /// - /// - /// - public static bool CheckScreenView(Vector3 point, Camera camera) + /// + /// Checks if a world space point is within our view frustum. + /// Excludes near/far planes but returns false if the point is behind the camera. + /// + /// World space point to check. + /// Unity Camera used for world-camera space conversion (usually left camera) + /// + public static bool CheckScreenView(Vector3 point, Camera camera) { //Transform the point into screen space Vector3 screenpoint = camera.WorldToScreenPoint(point); @@ -411,33 +473,46 @@ public static bool CheckScreenView(Vector3 point, Camera camera) } - /*********************************************************************************************** + /*********************************************************************************************** ****************************** IMAGE UTILS ********************************** ***********************************************************************************************/ - static public bool SaveImage(RenderTexture rt, string path = "Assets/image.png") + /// + /// Saves a RenderTexture to a .png in the given relative path. Saved to Assets/image.png by default. + /// Use this to take a picture of the ZED's final output. + /// + /// If in pass-through AR mode, you can pass ZEDRenderingPlane.target to this from the ZEDRenderingPlane + /// components in the ZED's left eye. If not using AR, you can create your own RenderTexture, and use + /// Graphics.Blit to copy to it in an OnRenderImage function of a component you attach to the camera. + /// + /// Source RenderTexture to be saved. + /// Path and filename to save the file. + /// + static public bool SaveImage(RenderTexture rt, string path = "Assets/image.png") { if (rt == null || path.Length == 0) return false; - RenderTexture currentActiveRT = RenderTexture.active; - RenderTexture.active = rt; + RenderTexture currentActiveRT = RenderTexture.active; //Cache the currently active RenderTexture to avoid interference. + RenderTexture.active = rt; //Switch the source RenderTexture to the active one. - Texture2D tex = new Texture2D(rt.width, rt.height); + Texture2D tex = new Texture2D(rt.width, rt.height); //Make a Texture2D copy of it and save it. tex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0); System.IO.File.WriteAllBytes(path, tex.EncodeToPNG()); - RenderTexture.active = currentActiveRT; + RenderTexture.active = currentActiveRT; //Restore the old active RenderTexture. return true; } - /*********************************************************************************************** + /*********************************************************************************************** ****************************** MATH UTILS ********************************** ***********************************************************************************************/ - public static float DistancePointLine(Vector3 point, Vector3 lineStartPoint, Vector3 lineEndPoint) + + public static float DistancePointLine(Vector3 point, Vector3 lineStartPoint, Vector3 lineEndPoint) { return Vector3.Magnitude(ProjectPointLine(point, lineStartPoint, lineEndPoint) - point); } + public static Vector3 ProjectPointLine(Vector3 point, Vector3 lineStart, Vector3 lineEnd) { Vector3 rhs = point - lineStart; diff --git a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs index a2ce71aa..54aa67a9 100644 --- a/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs @@ -8,82 +8,113 @@ #endif - - +/// +/// The central script of the ZED Unity plugin, and the primary way a developer can interact with the camera. +/// It sets up and closes connection to the ZED, adjusts parameters based on user settings, enables/disables/handles +/// features like tracking, and holds numerous useful properties, methods, and callbacks. +/// +/// +/// ZEDManager is attached to the root objects in the ZED_Rig_Mono and ZED_Rig_Stereo prefabs. +/// If using ZED_Rig_Stereo, it will set isStereoRig to true, which triggers several behaviors unique to stereo pass-through AR. +/// public class ZEDManager : MonoBehaviour { - // Set to true to activate dll wrapper verbose file (C:/ProgramData/STEREOLABS/SL_Unity_wrapper.txt) - // Default: false - // Warning: this can decrease performance. Use only for debugging. + /// + /// For advanced debugging. Default false. Set true for the Unity wrapper to log all SDK calls to a new file + /// at C:/ProgramData/stereolabs/SL_Unity_wrapper.txt. This helps find issues that may occur within + /// the protected .dll, but can decrease performance. + /// private bool wrapperVerbose = false; //////////////////////////// //////// Public /////////// //////////////////////////// /// - /// Current instance of the ZED Camera + /// Current instance of the ZED Camera, which handles calls to the Unity wrapper .dll. /// public sl.ZEDCamera zedCamera; - [Header("Camera")] /// - /// Selected resolution + /// Resolution setting for all images retrieved from the camera. Higher resolution means lower framerate. + /// HD720 is strongly recommended for pass-through AR. /// + [Header("Camera")] + [Tooltip("Resolution setting for all images retrieved from the camera. Higher resolution means lower framerate. " + + "HD720 is strongly recommended for pass-through AR.")] public sl.RESOLUTION resolution = sl.RESOLUTION.HD720; /// - /// Targeted FPS + /// Targeted FPS, based on the resolution. VGA = 100, HD720 = 60, HD1080 = 30, HD2K = 15. /// private int FPS = 60; /// - /// Depth mode + /// The accuracy of depth calculations. Higher settings mean more accurate occlusion and lighting but costs performance. + /// Note there's a significant jump in performance cost between QUALITY and ULTRA modes. /// + [Tooltip("The accuracy of depth calculations. Higher settings mean more accurate occlusion and lighting but costs performance.")] public sl.DEPTH_MODE depthMode = sl.DEPTH_MODE.PERFORMANCE; - - [Header("Motion Tracking")] /// - /// Enables the tracking, if true, the tracking computed will be set to the gameObject. - /// If false, the camera tracking will be done by HMD if connected and available + /// If enabled, the ZED will move/rotate itself using its own inside-out tracking. + /// If false, the camera tracking will move with the VR HMD if connected and available. + /// Normally, ZEDManager's GameObject will move according to the tracking. But if in AR pass-through mode, + /// then the Camera_eyes object in ZED_Rig_Stereo will move while this object stays still. /// + [Header("Motion Tracking")] + [Tooltip("If enabled, the ZED will move/rotate itself using its own inside-out tracking. " + + "If false, the camera tracking will move with the VR HMD if connected and available.")] public bool enableTracking = true; /// /// Enables the spatial memory. Will detect and correct tracking drift by remembering features and anchors in the environment, /// but may cause visible jumps when it happens. /// - [Tooltip("Will detect and correct tracking drift by remembering features and anchors in the environment, but may cause visible jumps when it happens")] + [Tooltip("Enables the spatial memory. Will detect and correct tracking drift by remembering features and anchors in the environment, " + + "but may cause visible jumps when it happens")] public bool enableSpatialMemory = true; /// - /// Area file path + /// If using Spatial Memory, you can specify a path to an existing .area file to start with some memory already loaded. + /// .area files are created by scanning a scene with ZEDSpatialMappingManager and saving the scan. /// + [Tooltip("If using Spatial Memory, you can specify a path to an existing .area file to start with some memory already loaded. " + + ".area files are created by scanning a scene with ZEDSpatialMappingManager and saving the scan.")] public string pathSpatialMemory = "ZED_spatial_memory"; + /// - /// Available Rendering path as ZEDRenderingMode + /// Rendering paths available to the ZED with the corresponding Unity rendering path. /// public enum ZEDRenderingMode { FORWARD = RenderingPath.Forward, DEFERRED = RenderingPath.DeferredShading }; - - [Header("Rendering")] + /// - /// Activate/Deactivate depth comparison between Real and Virtual (depth occlusions) + /// When enabled, the real world can occlude (cover up) virtual objects that are behind it. + /// Otherwise, virtual objects will appear in front. /// - [Tooltip("Activate/Deactivate depth Real/Virtual comparison and occlusions")] + [Header("Rendering")] + [Tooltip("When enabled, the real world can occlude (cover up) virtual objects that are behind it. " + + "Otherwise, virtual objects will appear in front.")] public bool depthOcclusion = true; /// - /// AR post processing: Real and Virtual blending + /// Enables post-processing effects on virtual objects that blends them in with the real world. /// - [LabelOverride("AR Post-processing","Adjust virtual objects rendering for a better fit on the real scene")] + [LabelOverride("AR Post-Processing")] + [Tooltip("Enables post-processing effects on virtual objects that blends them in with the real world.")] public bool postProcessing = true; /// - /// Camera or Image brightness + /// Brightness of the final real-world image. Default is 1. Lower to darken the environment in a realistic-looking way. + /// This is a rendering setting that doesn't affect the raw input from the camera. /// [Range(0, 1)] + [Tooltip("Brightness of the final real-world image. Default is 1. Lower to darken the environment in a realistic-looking way. " + + "This is a rendering setting that doesn't affect the raw input from the camera.")] public float m_cameraBrightness = 1.0f; + /// + /// Public accessor for m_cameraBrightness, which is the post-capture brightness setting of the real-world image. + /// public float CameraBrightness { get {return m_cameraBrightness;} @@ -94,48 +125,75 @@ public float CameraBrightness OnCamBrightnessChange(m_cameraBrightness); } } + /// + /// Delegate for OnCamBrightnessChange, which is used to update shader properties when the brightness setting changes. + /// + /// public delegate void onCamBrightnessChangeDelegate(float newVal); + /// + /// Event fired when the camera brightness setting is changed. Used to update shader properties. + /// public event onCamBrightnessChangeDelegate OnCamBrightnessChange; + //Strings used for the Status display in the Inspector. + /// + /// Version of the installed ZED SDK, for display in the Inspector. + /// [Header("Status")] [ReadOnly("Version")] [HideInInspector] public string versionZED = "-"; + /// + /// How many frames per second the engine is rendering, for display in the Inspector. + /// [ReadOnly("Engine FPS")] [HideInInspector] public string engineFPS = "-"; + /// + /// How many images per second are received from the ZED, for display in the Inspector. + /// [ReadOnly("Camera FPS")] [HideInInspector] public string cameraFPS = "-"; + /// + /// The connected VR headset, if any, for display in the Inspector. + /// [ReadOnly("HMD Device")] [HideInInspector] public string HMDDevice = "-"; + /// + /// Whether the ZED's tracking is on, off, or searching (lost position, trying to recover) for display in the Inspector. + /// [ReadOnly("Tracking State")] [HideInInspector] public string trackingState = "-"; - //////////////////////////// //////// Private /////////// //////////////////////////// /// - /// Init parameters to the ZED (parameters of open()) + /// Initialization parameters used to start the ZED. Holds settings that can't be changed at runtime + /// (resolution, depth mode, .SVO path, etc.). /// private sl.InitParameters initParameters; /// - /// Runtime parameters to the ZED (parameters of grab()) + /// Runtime parameters used to grab a new image. Settings can change each frame, but are lower level + /// (sensing mode, point cloud, if depth is enabled, etc.). /// private sl.RuntimeParameters runtimeParameters; /// - /// Activate/Deactivate depth stabilizer + /// Enables the ZED SDK's depth stabilizer, which improves depth accuracy and stability. There's rarely a reason to disable this. /// private bool depthStabilizer = true; /// - /// Is camera moving + /// Whether the camera is currently being tracked using the ZED's inside-out tracking. /// private bool isZEDTracked = false; /// - /// Checks if the tracking has been activated + /// Whether the ZED's inside-out tracking has been activated. /// private bool isTrackingEnable = false; /// - /// Checks if the camera tracked in any way (hmd, zed, ...) + /// Whether the camera is tracked in any way (ZED's tracking or a VR headset's tracking). /// private bool isCameraTracked = false; + /// + /// Public accessor for whether the camera is tracked in any way (ZED's tracking or a VR headset's tracking). + /// public bool IsCameraTracked { get { return isCameraTracked; } @@ -143,45 +201,47 @@ public bool IsCameraTracked /// - /// Orientation returned by the tracker + /// Orientation last returned by the ZED's tracking. /// private Quaternion zedOrientation = Quaternion.identity; /// - /// Position returned by the tracker + /// Position last returned by the ZED's tracking. /// private Vector3 zedPosition = new Vector3(); /// - /// Manages the read and write of SVO + /// Instance of the manager that handles reading/recording SVO files, which are video files + /// with metadata that you can treat like regular ZED input. /// private ZEDSVOManager zedSVOManager; - + /// - /// Starting Position (not used in Stereo AR) + /// Position of the camera (zedRigRoot) when the scene starts. Not used in Stereo AR. /// private Vector3 initialPosition = new Vector3(); /// - /// Starting Orientation (not used in Stereo AR) + /// Orientation of the camera (zedRigRoot) when the scene starts. Not used in Stereo AR. /// private Quaternion initialRotation = Quaternion.identity; /// - /// Sensing mode - /// Always use the sensing mode FILL, since we need a depth without holes + /// Sensing mode: STANDARD or FILL. FILL corrects for missing depth values. + /// Almost always better to use FILL, since we need depth without holes for proper occlusion. /// private sl.SENSING_MODE sensingMode = sl.SENSING_MODE.FILL; /// - /// Rotation offset used to retrieve the tracking with an offset of rotation + /// Rotation offset used to retrieve the tracking with a rotational offset. /// private Quaternion rotationOffset; /// - /// Position offset used to retrieve the tracking with an offset of position + /// Position offset used to retrieve the tracking with a positional offset. /// private Vector3 positionOffset; /// - /// Enables the pose smoothing during drift correction (for MR experience, it is advised to leave it at true when spatial memory is activated) + /// Enables pose smoothing during drift correction. For AR, this is especially important when + /// spatial memory is activated. /// private bool enablePoseSmoothing = false; /// - /// The engine FPS. + /// The engine FPS, updated every frame. /// private float fps_engine = 90.0f; @@ -191,49 +251,55 @@ public bool IsCameraTracked /////////////////////////////////////// /// - /// Flag to check is AR mode is activated + /// Whether AR mode is activated. /// private static bool isStereoRig = false; + /// + /// Whether AR mode is activated. Assigned by ZEDManager.CheckStereoMode() in Awake(). + /// Will be true if the ZED_Rig_Stereo prefab (or a similarly-structured prefab) is used. + /// public static bool IsStereoRig { get { return isStereoRig; } } /// - /// Checks if the thread init is over + /// Checks if the ZED has finished initializing. /// private bool zedReady = false; + /// + /// Checks if the ZED has finished initializing. + /// public bool IsZEDReady { get { return zedReady; } } /// - /// Tracking state used by anti-drift + /// Flag set to true if the camera was connected and the wasn't anymore. + /// Causes ZEDDisconnected() to be called each frame, which attemps to restart it. + /// + private bool isDisconnected = false; + + /// + /// Current state of tracking: On, Off, or Searching (lost tracking, trying to recover). Used by anti-drift. /// private sl.TRACKING_STATE zedtrackingState = sl.TRACKING_STATE.TRACKING_OFF; + /// + /// Current state of tracking: On, Off, or Searching (lost tracking, trying to recover). Used by anti-drift. + /// public sl.TRACKING_STATE ZEDTrackingState { get { return zedtrackingState; } } - /// - /// First position registered after enabling the tracking + /// First position registered after the tracking has started (whether via ZED or a VR HMD). /// - private Vector3 originPosition; - public Vector3 OriginPosition - { - get { return originPosition; } - } - + public Vector3 OriginPosition { get; private set; } /// - /// First rotation registered after enabling the tracking + /// First rotation/orientation registered after the tracking has started (whether via ZED or a VR HMD). /// - private Quaternion originRotation; - public Quaternion OriginRotation - { - get { return originRotation; } - } + public Quaternion OriginRotation { get; private set; } /////////////////////////////////////////////////// @@ -245,68 +311,79 @@ public Quaternion OriginRotation /// - /// Image acquisition thread + /// Image acquisition thread. /// - private Thread threadGrab = null; //Thread - public object grabLock = new object(); // lock - private bool running = false; //state + private Thread threadGrab = null; + /// + /// Mutex for the image acquisition thread. + /// + public object grabLock = new object(); + /// + /// State of the image acquisition thread. + /// + private bool running = false; /// - /// Opening Thread + /// Initialization thread. + /// + private Thread threadOpening = null; + /// + /// Result of the latest attempt to initialize the ZED. + /// + public static sl.ERROR_CODE LastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; + /// + /// Result of last frame's attempt to initialize the ZED. /// - public static sl.ERROR_CODE LastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; //Result State public static sl.ERROR_CODE PreviousInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; - private bool openingLaunched; // Init State - private Thread threadOpening = null; //Thread - - /// - /// Thread to init the tracking (the tracking takes some time to Init) + /// State of the ZED initialization thread. + /// + private bool openingLaunched; + + /// + /// Tracking initialization thread. Used as the tracking takes some time to start. /// private Thread trackerThread; - /////////////////////////////////////////// - ////// camera and player Transforms ////// + ////// Camera and Player Transforms ////// /////////////////////////////////////////// /// - /// Contains the transform of the camera left + /// Transform of the left camera in the ZED rig. /// private Transform cameraLeft = null; /// - /// Contains the transform of the right camera if enabled + /// Transform of the right camera in the ZED rig. Only exists in a stereo rig (like ZED_Rig_Stereo). /// private Transform cameraRight = null; /// - ///Contains the position of the player's head, different from ZED's position - /// But the position of the ZED regarding this transform does not change during use (rigid transform) + /// Contains the position of the player's head, which is different from the ZED's position in AR mode. + /// But its position relative to the ZED does not change during use (it's a rigid transform). /// In ZED_Rig_Mono, this will be the root ZED_Rig_Mono object. In ZED_Rig_Stereo, this is Camera_eyes. /// private Transform zedRigRoot = null; - /// - /// Get the center transform, the only one moved by the tracker on AR + /// Gets the center transform, which is the transform moved by the tracker in AR mode. + /// This is the root object in ZED_Rig_Mono, and Camera_eyes in ZED_Rig_Stereo. /// - /// public Transform GetZedRootTansform() { return zedRigRoot; } /// - /// Get the left camera. It's best to use this one as it's available in all configurations + /// Gets the left camera in the ZED rig. It's best to use this one as it's available in all configurations. /// - /// public Transform GetLeftCameraTransform() { return cameraLeft; } /// - /// Get the right camera, only available on AR + /// Get the right camera in the ZED rig. Only available in the stereo rig (ZED_Rig_Stereo). /// /// public Transform GetRightCameraTransform() @@ -319,20 +396,39 @@ public Transform GetRightCameraTransform() ///////////////////////////////////// ////// Timestamps ////// ///////////////////////////////////// + + /// + /// Timestamp of the last ZED image grabbed. Textures from this grab may not have updated yet. + /// private ulong cameraTimeStamp = 0; + /// + /// Timestamp of the last ZED image grabbed. Textures from this grab may not have updated yet. + /// public ulong CameraTimeStamp { get { return cameraTimeStamp; } } + /// + /// Timestamp of the images used to create the current textures. + /// private ulong imageTimeStamp = 0; + /// + /// Timestamp of the images used to create the current textures. + /// public ulong ImageTimeStamp { get { return imageTimeStamp; } } - + /// + /// Whether the grabbing thread should grab a new frame from the ZED SDK. + /// True unless the last grabbed frame hasn't been applied yet, or the ZED isn't initialized. + /// private bool requestNewFrame = false; + /// + /// Whether a new frame has been grabbed from the ZED SDK that needs to be updated. + /// private bool newFrameAvailable = false; @@ -340,32 +436,62 @@ public ulong ImageTimeStamp ///////////////////////////////////// ////// Layers for ZED ////// ///////////////////////////////////// + + /// + /// Layer that the left canvas GameObject (showing the image from the left eye) is set to. + /// The right camera in ZED_Rig_Stereo can't see this layer. + /// private int layerLeftScreen = 8; + /// + /// Layer that the right canvas GameObject (showing the image from the right eye) is set to. + /// The left camera in ZED_Rig_Stereo can't see this layer. + /// private int layerRightScreen = 10; + /// + /// Layer that the final left image canvas in the hidden AR rig is set to. (See CreateZEDRigDisplayer()) + /// Hidden from all ZED cameras except the final left camera. + /// private int layerLeftFinalScreen = 9; + /// + /// Layer that the final right image canvas in the hidden AR rig is set to. (See CreateZEDRigDisplayer()) + /// Hidden from all ZED cameras except the final right camera. + /// private int layerRightFinalScreen = 11; - ///////////////////////////////////// - ////// ZED specific events ////// - ///////////////////////////////////// - /// Event when ZED is Ready + ///////////////////////////////////// + ////// ZED specific events ////// + ///////////////////////////////////// + + /// + /// Delegate for OnZEDReady. + /// public delegate void OnZEDManagerReady(); + /// + /// Called when the ZED has finished initializing successfully. + /// Used by many scripts to run startup logic that requires that the ZED is active. + /// public static event OnZEDManagerReady OnZEDReady; - /// Event when ZED is disconnected + /// + /// Delegate for OnZEDDisconnected. + /// public delegate void OnZEDManagerDisconnected(); + /// + /// Event called when ZED was running but became disconnected. + /// public static event OnZEDManagerDisconnected OnZEDDisconnected; - /// - /// ZED Manager Instance + /// ZEDManager instance for singleton implementation. /// // Static singleton instance private static ZEDManager instance; - // Static singleton property + /// + /// Singleton implementation: Gets the scene's instance of ZEDManager, and creates one in if nonexistant. + /// public static ZEDManager Instance { get { return instance ?? (instance = new GameObject("ZEDManager").AddComponent()); } @@ -375,17 +501,19 @@ public static ZEDManager Instance #region CHECK_AR /// - /// Check if there are two cameras, one for each eye as children + /// Checks if this GameObject is a stereo rig. Requires a child object called 'Camera_eyes' and + /// two cameras as children of that object, one with stereoTargetEye set to Left, the other two Right. + /// Regardless, sets references to leftCamera and (if relevant) rightCamera and sets their culling masks. /// private void CheckStereoMode() { - zedRigRoot = gameObject.transform; + zedRigRoot = gameObject.transform; //The object moved by tracking. By default it's this Transform. May get changed. bool devicePresent = UnityEngine.VR.VRDevice.isPresent; if (gameObject.transform.childCount > 0 && gameObject.transform.GetChild(0).gameObject.name.Contains("Camera_eyes")) { - + //Camera_eyes object exists. Now check all cameras in its children for left- and right-eye cameras. Component[] cams = gameObject.transform.GetChild(0).GetComponentsInChildren(typeof(Camera)); foreach (Camera cam in cams) { @@ -411,7 +539,7 @@ private void CheckStereoMode() } } } - else + else //No Camera_eyes object exists. It's a mono rig. Set child cameras to a non-VR eye. { Component[] cams = gameObject.transform.GetComponentsInChildren(typeof(Camera)); foreach (Camera cam in cams) @@ -427,13 +555,13 @@ private void CheckStereoMode() - if (cameraLeft && cameraRight) + if (cameraLeft && cameraRight) //We found a Camera_eyes object and both a left- and right-eye camera. { isStereoRig = true; if (cameraLeft.transform.parent != null) - zedRigRoot = cameraLeft.transform.parent; + zedRigRoot = cameraLeft.transform.parent; //Make Camera_eyes the new zedRigRoot to be tracked. } - else + else //Not all conditions for a stereo rig were met. Set culling masks accordingly. { isStereoRig = false; Camera temp = cameraLeft.gameObject.GetComponent(); @@ -441,9 +569,9 @@ private void CheckStereoMode() if (cameraLeft.transform.parent != null) zedRigRoot = cameraLeft.transform.parent; - foreach (Camera c in Camera.allCameras) + foreach (Camera c in Camera.allCameras) //Child cameras to leftCamera get matching cullingMasks. { - if (c != temp) + if (c != temp) { c.cullingMask &= ~(1 << layerLeftScreen); c.cullingMask &= ~(1 << sl.ZEDCamera.Tag); @@ -459,8 +587,10 @@ private void CheckStereoMode() /// - /// Set the layer number to the game object layer + /// Sets the target GameObject and all its children to the specified layer. /// + /// Target GameObject. + /// Layer that the GameObject and all children will be set to. public static void SetLayerRecursively(GameObject go, int layerNumber) { if (go == null) return; @@ -472,20 +602,20 @@ public static void SetLayerRecursively(GameObject go, int layerNumber) /// - /// Stops the current thread + /// Stops the initialization and grabbing threads. /// public void Destroy() { running = false; - // In case the opening thread is still running + //In case the opening thread is still running. if (threadOpening != null) { threadOpening.Join(); threadOpening = null; } - // Shutdown grabbing thread + //Shut down the image grabbing thread. if (threadGrab != null) { threadGrab.Join(); @@ -496,13 +626,14 @@ public void Destroy() } /// - /// Raises the application quit event + /// Called by Unity when the application is closed. + /// Also called by Reset() to properly start from a 'clean slate.' /// void OnApplicationQuit() { zedReady = false; OnCamBrightnessChange -= CameraBrightnessChangeHandler; - Destroy(); + Destroy(); //Close the grab and initialization threads. if (zedCamera != null) { @@ -513,52 +644,51 @@ void OnApplicationQuit() zedCamera.DisableRecording(); } } - zedCamera.Destroy(); + zedCamera.Destroy(); zedCamera = null; } } - - + /// + /// Sets up starting properties and starts the ZED initialization co-routine. + /// void Awake() { instance = this; zedReady = false; - //If you want the ZEDRig not to be destroyed - DontDestroyOnLoad(transform.root); + + DontDestroyOnLoad(transform.root); //If you want the ZED rig not to be destroyed when loading a scene. - //Init the first parameters + //Set first few parameters for initialization. This will get passed to the ZED SDK when initialized. initParameters = new sl.InitParameters(); initParameters.resolution = resolution; initParameters.depthMode = depthMode; initParameters.depthStabilization = depthStabilizer; - //Check if the AR is needed and if possible to add + //Check if this rig is a stereo rig. Will set isStereoRig accordingly. CheckStereoMode(); - //Init the other options + //Set initialization parameters that may change depending on what was done in CheckStereoMode(). isZEDTracked = enableTracking; initialPosition = zedRigRoot.transform.localPosition; zedPosition = initialPosition; zedOrientation = initialRotation; - - //Create a camera and return an error message if the dependencies are not detected + //Create a ZEDCamera instance and return an error message if the ZED SDK's dependencies are not detected. zedCamera = sl.ZEDCamera.GetInstance(); LastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; - zedSVOManager = GetComponent(); + zedSVOManager = GetComponent(); zedCamera.CreateCamera(wrapperVerbose); - if (zedSVOManager != null) + if (zedSVOManager != null) //If we have a ZEDSVOManager, change settings to read to/write from it. { - //Create a camera - if ((zedSVOManager.read || zedSVOManager.record) && zedSVOManager.videoFile.Length == 0) + if ((zedSVOManager.read || zedSVOManager.record) && zedSVOManager.videoFile.Length == 0) //Path to SVO is empty. { zedSVOManager.record = false; zedSVOManager.read = false; } - if (zedSVOManager.read) + if (zedSVOManager.read) //Playing back an SVO. We'll use that for input instead of actual ZED. { zedSVOManager.record = false; initParameters.pathSVO = zedSVOManager.videoFile; @@ -570,29 +700,29 @@ void Awake() versionZED = "[SDK]: " + sl.ZEDCamera.GetSDKVersion().ToString() + " [Plugin]: " + sl.ZEDCamera.PluginVersion.ToString(); - //Set the ZED Tracking frame as Left eye + //Behavior specific to AR pass-through mode. if (isStereoRig) { - //Creates a CameraRig (the 2 last cameras) + //Creates a hidden camera rig that handles final output to the headset. GameObject o = CreateZEDRigDisplayer(); o.hideFlags = HideFlags.HideAndDontSave; o.transform.parent = transform; - //Force some initParameters that are required for MR experience - initParameters.enableRightSideMeasure = isStereoRig; - initParameters.depthMinimumDistance = 0.1f; - initParameters.depthStabilization = depthStabilizer; + //Force some initParameters that are required for a good AR experience. + initParameters.enableRightSideMeasure = isStereoRig; //Creates a depth map for both eyes, not just one. + initParameters.depthMinimumDistance = 0.1f; //Allow depth calculation to very close objects. + initParameters.depthStabilization = depthStabilizer; //Improve depth stability and accuracy. - //Create the mirror, the texture from the firsts cameras is rendered to avoid a black border + //For the Game/output window, mirror the headset view using a custom script that avoids stretching. CreateMirror(); } - //Start the co routine to initialize the ZED and avoid to block the user + //Starts a coroutine that initializes the ZED without freezing the game. LastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; openingLaunched = false; StartCoroutine("InitZED"); - OnCamBrightnessChange += CameraBrightnessChangeHandler; + OnCamBrightnessChange += CameraBrightnessChangeHandler; //Subscribe event for adjusting brightness setting. } @@ -601,7 +731,7 @@ void Awake() #region INITIALIZATION /// - /// ZED opening function (should be called in the thread) + /// ZED opening function. Should be called in the initialization thread (threadOpening). /// void OpenZEDInBackground() { @@ -612,7 +742,7 @@ void OpenZEDInBackground() /// - /// Initialization routine + /// Initialization coroutine. /// private uint numberTriesOpening = 0;/// Counter of tries to open the ZED const int MAX_OPENING_TRIES = 50; @@ -622,11 +752,11 @@ System.Collections.IEnumerator InitZED() while (LastInitStatus != sl.ERROR_CODE.SUCCESS) { //Initialize the camera - if (!openingLaunched) + if (!openingLaunched) //Don't try initializing again if the last attempt is still going. { - threadOpening = new Thread(new ThreadStart(OpenZEDInBackground)); + threadOpening = new Thread(new ThreadStart(OpenZEDInBackground)); //Assign thread. - if (LastInitStatus != sl.ERROR_CODE.SUCCESS) + if (LastInitStatus != sl.ERROR_CODE.SUCCESS) //If it failed, report it and log one failure. { #if UNITY_EDITOR numberTriesOpening++; @@ -635,9 +765,9 @@ System.Collections.IEnumerator InitZED() Debug.LogWarning("[ZEDPlugin]: " + LastInitStatus); } - if (numberTriesOpening > MAX_OPENING_TRIES) + if (numberTriesOpening > MAX_OPENING_TRIES) //Failed too many times. Give up. { - Debug.Log("[ZEDPlugin]: Stops initialization"); + Debug.Log("[ZEDPlugin]: Stopping initialization."); yield break; } #endif @@ -647,44 +777,43 @@ System.Collections.IEnumerator InitZED() } - threadOpening.Start(); + threadOpening.Start(); } yield return new WaitForSeconds(0.3f); } - //ZED has opened + //ZED has initialized successfully. if (LastInitStatus == sl.ERROR_CODE.SUCCESS) { threadOpening.Join(); - //Initialize the threading mode, the positions with the AR and the SVO if needed - //Launch the threading to enable the tracking + //Initialize the tracking thread, AR initial transforms and SVO read/write as needed. ZEDReady(); - //Wait until the ZED of the init of the tracking + //If using tracking, wait until the tracking thread has been initialized. while (enableTracking && !isTrackingEnable) { yield return new WaitForSeconds(0.5f); } - //Calls all the observers, the ZED is ready :) + //Tells all the listeners that the ZED is ready! :) if (OnZEDReady != null) { OnZEDReady(); } + //Make sure the screen is at 16:9 aspect ratio or close. Warn the user otherwise. float ratio = (float)Screen.width / (float)Screen.height; float target = 16.0f / 9.0f; if (Mathf.Abs(ratio - target) > 0.01) { - ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SCREEN_RESOLUTION); + Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SCREEN_RESOLUTION)); } - - //If not already launched, launch the grabbing thread + //If not already launched, launch the image grabbing thread. if (!running) { @@ -697,106 +826,105 @@ System.Collections.IEnumerator InitZED() } zedReady = true; - isDisconnected = false; //In case we just regained connection + isDisconnected = false; //In case we just regained connection. - setRenderingSettings(); - AdjustZEDRigCameraPosition(); + setRenderingSettings(); //Find the ZEDRenderingPlanes in the rig and configure them. + AdjustZEDRigCameraPosition(); //If in AR mode, move cameras to proper offset relative to zedRigRoot. } } /// - /// Adjust camera(s) and render plane position regarding zedRigRoot (player) transform - /// The ZED Rig will then only be moved using zedRigRoot transform (each camera will keep its local position regarding zedRigRoot) + /// Adjust camera(s) relative to zedRigRoot transform, which is what is moved each frame. Called at start of tracking. + /// In AR mode, offset is each camera's position relative to center of the user's head. Otherwise, cameras are just spaced + /// by the camera's baseline/IPD, or no offset is applied if there's just one camera. /// void AdjustZEDRigCameraPosition() { Vector3 rightCameraOffset = new Vector3(zedCamera.Baseline, 0.0f, 0.0f); - if (isStereoRig && VRDevice.isPresent) + if (isStereoRig && VRDevice.isPresent) //Using AR pass-through mode. { - // zedRigRoot transform (origin of the global camera) is placed on the HMD headset. Therefore we move the camera in front of it ( offsetHmdZEDPosition) - // as when the camera is mount on the HMD. Values are provided by default. This can be done with a calibration as well - // to know the exact position of the HMD regarding the camera + //zedRigRoot transform (origin of the global camera) is placed on the HMD headset. Therefore, we move the + //camera in front of it by offsetHmdZEDPosition to compensate for the ZED's position on the headset. + //If values are wrong, tweak calibration file created in ZEDMixedRealityPlugin. cameraLeft.localPosition = ar.HmdToZEDCalibration.translation; cameraLeft.localRotation = ar.HmdToZEDCalibration.rotation; - if (cameraRight) cameraRight.localPosition = cameraLeft.localPosition + new Vector3(zedCamera.Baseline, 0.0f, 0.0f); + if (cameraRight) cameraRight.localPosition = cameraLeft.localPosition + rightCameraOffset; //Space the eyes apart. if (cameraRight) cameraRight.localRotation = cameraLeft.localRotation; } - else if (isStereoRig && !VRDevice.isPresent) + else if (isStereoRig && !VRDevice.isPresent) //Using stereo rig, but no VR headset. { - // When no Hmd is available, simply put the origin at the left camera. + //When no VR HMD is available, simply put the origin at the left camera. cameraLeft.localPosition = Vector3.zero; cameraLeft.localRotation = Quaternion.identity; - if (cameraRight) cameraRight.localPosition = rightCameraOffset; + if (cameraRight) cameraRight.localPosition = rightCameraOffset; //Space the eyes apart. if (cameraRight) cameraRight.localRotation = Quaternion.identity; } - else + else //Using mono rig (ZED_Rig_Mono). No offset needed. { cameraLeft.localPosition = Vector3.zero; cameraLeft.localRotation = Quaternion.identity; } } - /// - /// Set the rendering settings (rendering path, shaders values) for camera Left and right - /// Activate/Deactivate depth occlusions, Change rendering path... + /// Find the ZEDRenderingPlane components in the ZED rig and set their rendering settings + /// (rendering path, shader values, etc.) for left and right cameras. Also activate/deactivate depth occlusions. /// void setRenderingSettings() { - - - ZEDRenderingPlane textureLeftOverlay = GetLeftCameraTransform().GetComponent(); - textureLeftOverlay.SetPostProcess(postProcessing); + ZEDRenderingPlane leftRenderingPlane = GetLeftCameraTransform().GetComponent(); + leftRenderingPlane.SetPostProcess(postProcessing); GetLeftCameraTransform().GetComponent().renderingPath = RenderingPath.UsePlayerSettings; Shader.SetGlobalFloat("_ZEDFactorAffectReal", m_cameraBrightness); - ZEDRenderingPlane textureRightOverlay = null; + ZEDRenderingPlane rightRenderingPlane = null; if (IsStereoRig) { - textureRightOverlay = GetRightCameraTransform().GetComponent(); - textureRightOverlay.SetPostProcess(postProcessing); + rightRenderingPlane = GetRightCameraTransform().GetComponent(); + rightRenderingPlane.SetPostProcess(postProcessing); } ZEDRenderingMode renderingPath = (ZEDRenderingMode)GetLeftCameraTransform().GetComponent().actualRenderingPath; - //Check that we are in forward or deffered - if (renderingPath != ZEDRenderingMode.FORWARD && renderingPath != ZEDRenderingMode.DEFERRED) { + //Make sure we're in either forward or deferred rendering. Default to forward otherwise. + if (renderingPath != ZEDRenderingMode.FORWARD && renderingPath != ZEDRenderingMode.DEFERRED) + { Debug.LogError ("[ZED Plugin] Only Forward and Deferred Shading rendering path are supported"); GetLeftCameraTransform ().GetComponent ().renderingPath = RenderingPath.Forward; if (IsStereoRig) GetRightCameraTransform ().GetComponent ().renderingPath = RenderingPath.Forward; } - //Set Depth Occ + //Set depth occlusion. if (renderingPath == ZEDRenderingMode.FORWARD) { - textureLeftOverlay.ManageKeyWordPipe(!depthOcclusion, "NO_DEPTH_OCC"); - if (textureRightOverlay) - textureRightOverlay.ManageKeyWordPipe(!depthOcclusion, "NO_DEPTH_OCC"); + leftRenderingPlane.ManageKeywordPipe(!depthOcclusion, "NO_DEPTH_OCC"); + if (rightRenderingPlane) + rightRenderingPlane.ManageKeywordPipe(!depthOcclusion, "NO_DEPTH_OCC"); }else if (renderingPath == ZEDRenderingMode.DEFERRED) { - textureLeftOverlay.ManageKeyWordDefferedMat(!depthOcclusion, "NO_DEPTH_OCC"); - if (textureRightOverlay) - textureRightOverlay.ManageKeyWordDefferedMat(!depthOcclusion, "NO_DEPTH_OCC"); + leftRenderingPlane.ManageKeywordDeferredMat(!depthOcclusion, "NO_DEPTH_OCC"); + if (rightRenderingPlane) + rightRenderingPlane.ManageKeywordDeferredMat(!depthOcclusion, "NO_DEPTH_OCC"); } } #endregion - - #region IMAGE_ACQUIZ + /// + /// Continuously grabs images from the ZED. Runs on its own thread. + /// private void ThreadedZEDGrab() { - runtimeParameters = new sl.RuntimeParameters(); runtimeParameters.sensingMode = sensingMode; runtimeParameters.enableDepth = true; - // Don't change this ReferenceFrame. If we need normals in world frame, then we will do the convertion ourselves. + //Don't change this reference frame. If we need normals in the world frame, better to do the conversion ourselves. runtimeParameters.measure3DReferenceFrame = sl.REFERENCE_FRAME.CAMERA; while (running) @@ -809,6 +937,10 @@ private void ThreadedZEDGrab() } + /// + /// Grabs images from the ZED SDK and updates tracking, FPS and timestamp values. + /// Called from ThreadedZEDGrab() in a separate thread. + /// private void AcquireImages() { @@ -817,7 +949,7 @@ private void AcquireImages() sl.ERROR_CODE e = sl.ERROR_CODE.NOT_A_NEW_FRAME; - // Live or SVO ? if SVO is in pause, don't need to call grab again since image will not change + // Live or SVO? If SVO is paused, we don't need to call Grab() again as the image will not change. if (zedSVOManager == null) e = zedCamera.Grab (ref runtimeParameters); else { @@ -876,17 +1008,16 @@ private void AcquireImages() } else { - //to avoid "overheat" + //To avoid "overheating." Thread.Sleep(1); } } #endregion - - /// - /// Init the SVO, and launch the thread to enable the tracking + /// Initialize the SVO, and launch the thread to initialize tracking. Called once the ZED + /// is initialized successfully. /// private void ZEDReady() { @@ -901,9 +1032,12 @@ private void ZEDReady() { if (zedSVOManager.record) { - if (zedCamera.EnableRecording(zedSVOManager.videoFile, zedSVOManager.compressionMode) != sl.ERROR_CODE.SUCCESS) + sl.ERROR_CODE svorec = zedCamera.EnableRecording(zedSVOManager.videoFile, zedSVOManager.compressionMode); + if (svorec != sl.ERROR_CODE.SUCCESS) { zedSVOManager.record = false; + Debug.LogError("SVO recording failed. Check that there is enough space on the drive and that the " + + "path provided is valid."); } } @@ -920,37 +1054,34 @@ private void ZEDReady() if (isStereoRig && VRDevice.isPresent) { ZEDMixedRealityPlugin.Pose pose = ar.InitTrackingAR(); - originPosition = pose.translation; - originRotation = pose.rotation; - zedRigRoot.localPosition = originPosition; - zedRigRoot.localRotation = originRotation; + OriginPosition = pose.translation; + OriginRotation = pose.rotation; + zedRigRoot.localPosition = OriginPosition; + zedRigRoot.localRotation = OriginRotation; if (!zedCamera.IsHmdCompatible && zedCamera.IsCameraReady) - Debug.LogWarning("WARNING : AR Passtrough with a ZED is not recommended. You may consider using the ZED-M, designed for that purpose"); + Debug.LogWarning("WARNING: AR Passtrough with a ZED is not recommended. Consider using ZED Mini, designed for this purpose."); } else { - originPosition = initialPosition; - originRotation = initialRotation; + OriginPosition = initialPosition; + OriginRotation = initialRotation; } #if UNITY_EDITOR UnityEditor.EditorApplication.playmodeStateChanged = HandleOnPlayModeChanged; #endif - - } /// - /// Enables the thread to get the trackingr.up + /// Initializes the ZED's inside-out tracking. Started as a separate thread in OnZEDReady. /// void EnableTrackingThreaded() { enablePoseSmoothing = enableSpatialMemory; lock (grabLock) { - - //Make sure we have "grabbed" on frame first + //Make sure we have grabbed a frame first. sl.ERROR_CODE e = zedCamera.Grab(ref runtimeParameters); int timeOut_grab = 0; while (e != sl.ERROR_CODE.SUCCESS && timeOut_grab < 100) @@ -960,16 +1091,16 @@ void EnableTrackingThreaded() timeOut_grab++; } - //Make sure the .area path is valid - if (pathSpatialMemory != "" && !System.IO.File.Exists(pathSpatialMemory)) + //If using spatial memory and given a path to a .area file, make sure that path is valid. + if (enableSpatialMemory && pathSpatialMemory != "" && !System.IO.File.Exists(pathSpatialMemory)) { Debug.Log("Specified path to .area file '" + pathSpatialMemory + "' does not exist. Ignoring."); pathSpatialMemory = ""; } - //Now enable the tracking with the proper parameters - //if (!(enableTracking = (zedCamera.EnableTracking(ref initialRotation, ref initialPosition, enableSpatialMemory, enablePoseSmoothing, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) - if (!(enableTracking = (zedCamera.EnableTracking(ref zedOrientation, ref zedPosition, enableSpatialMemory, enablePoseSmoothing, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) + //Now enable the tracking with the proper parameters. + if (!(enableTracking = (zedCamera.EnableTracking(ref zedOrientation, ref zedPosition, enableSpatialMemory, + enablePoseSmoothing, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) { throw new Exception(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_NOT_INITIALIZED)); } @@ -978,11 +1109,12 @@ void EnableTrackingThreaded() isTrackingEnable = true; } } - - } #if UNITY_EDITOR + /// + /// Handler for playmodeStateChanged. + /// void HandleOnPlayModeChanged() { @@ -998,30 +1130,28 @@ void HandleOnPlayModeChanged() #region ENGINE_UPDATE /// - /// If a new frame is available, this function retrieve the Images and update the texture at each engine tick - /// Called in Update() + /// If a new frame is available, this function retrieves the images and updates the Unity textures. Called in Update(). /// public void UpdateImages() { if (zedCamera == null) return; - if (newFrameAvailable) + if (newFrameAvailable) //ThreadedZEDGrab()/AcquireImages() grabbed images we haven't updated yet. { - lock (grabLock) { - zedCamera.RetrieveTextures(); - zedCamera.UpdateTextures(); + zedCamera.RetrieveTextures(); //Tell the wrapper to compute the textures. + zedCamera.UpdateTextures(); //Tell the wrapper to update the textures. imageTimeStamp = zedCamera.GetImagesTimeStamp(); } - requestNewFrame = true; + requestNewFrame = true; //Lets ThreadedZEDGrab/AcquireImages() start grabbing again. newFrameAvailable = false; } #region SVO Manager - if (zedSVOManager != null) + if (zedSVOManager != null) //If using an SVO, call SVO-specific functions. { if (!zedSVOManager.pause) { @@ -1040,7 +1170,7 @@ public void UpdateImages() { if (!(enableTracking = (zedCamera.ResetTracking(initialRotation, initialPosition) == sl.ERROR_CODE.SUCCESS))) { - throw new Exception("Error, tracking not available"); + throw new Exception("Error: Tracking not available after SVO playback has looped."); } zedRigRoot.localPosition = initialPosition; @@ -1060,29 +1190,31 @@ public void UpdateImages() /// - /// Get the tracking position from the ZED and update the manager's position. If enable, update the AR Tracking - /// Only called in LIVE mode - /// Called in Update() + /// Gets the tracking position from the ZED and updates zedRigRoot's position. Also updates the AR tracking if enabled. + /// Only called in Live (not SVO playback) mode. Called in Update(). /// private void UpdateTracking() { if (!zedReady) return; - if (isZEDTracked) { + if (isZEDTracked) //ZED inside-out tracking is enabled and initialized. + { Quaternion r; Vector3 v; isCameraTracked = true; - if (VRDevice.isPresent && isStereoRig) { - if (calibrationHasChanged) { - AdjustZEDRigCameraPosition (); + if (VRDevice.isPresent && isStereoRig) //AR pass-through mode. + { + if (calibrationHasChanged) //If the HMD offset calibration file changed during runtime. + { + AdjustZEDRigCameraPosition(); //Re-apply the ZED's offset from the VR headset. calibrationHasChanged = false; } - ar.ExtractLatencyPose (imageTimeStamp); - ar.AdjustTrackingAR (zedPosition, zedOrientation, out r, out v); + ar.ExtractLatencyPose (imageTimeStamp); //Find what HMD's pose was at ZED image's timestamp for latency compensation. + ar.AdjustTrackingAR (zedPosition, zedOrientation, out r, out v); zedRigRoot.localRotation = r; zedRigRoot.localPosition = v; @@ -1090,49 +1222,56 @@ private void UpdateTracking() ZEDSyncRotation = r; HMDSyncPosition = ar.LatencyPose ().translation; HMDSyncRotation = ar.LatencyPose ().rotation; - } else { + } + else //Not AR pass-through mode. + { zedRigRoot.localRotation = zedOrientation; zedRigRoot.localPosition = zedPosition; } - } else if (VRDevice.isPresent && isStereoRig) { + } else if (VRDevice.isPresent && isStereoRig) //ZED tracking is off but HMD tracking is on. Fall back to that. + { isCameraTracked = true; - ar.ExtractLatencyPose (imageTimeStamp); - zedRigRoot.localRotation = ar.LatencyPose ().rotation; + ar.ExtractLatencyPose (imageTimeStamp); //Find what HMD's pose was at ZED image's timestamp for latency compensation. + zedRigRoot.localRotation = ar.LatencyPose ().rotation; zedRigRoot.localPosition = ar.LatencyPose ().translation; - } else + } + else //The ZED is not tracked by itself or an HMD. isCameraTracked = false; } /// - /// Updates the collection of hmd pose (AR only) + /// Stores the HMD's current pose. Used in AR mode for latency compensation. + /// Pose will be applied to final canvases when a new image's timestamp matches + /// the time when this is called. /// - void updateHmdPose() + void UpdateHmdPose() { if (IsStereoRig && VRDevice.isPresent) - ar.CollectPose(); + ar.CollectPose(); //Save headset pose with current timestamp. } /// - /// Update this instance. Called at each frame + /// Updates images, collects HMD poses for latency correction, and applies tracking. + /// Called by Unity each frame. /// void Update() { - // Update Image first, then collect HMD pose at the image time. - // Then update the tracking - UpdateImages(); - updateHmdPose(); - UpdateTracking(); + // Then update the tracking + UpdateImages(); //Image is updated first so we have its timestamp for latency compensation. + UpdateHmdPose(); //Store the HMD's pose at the current timestamp. + UpdateTracking(); //Apply position/rotation changes to zedRigRoot. - //If the ZED is disconnected, to easily look at the message + //Check if ZED is disconnected; invoke event and call function if so. if (isDisconnected) { if (OnZEDDisconnected != null) - OnZEDDisconnected(); + OnZEDDisconnected(); //Invoke event. Used for GUI message and pausing ZEDRenderingPlanes. - ZEDDisconnected(); + ZEDDisconnected(); //Tries to reset the camera. } #if UNITY_EDITOR + //Update strings used for displaying stats in the Inspector. if (zedCamera != null) { float frame_drop_count = zedCamera.GetFrameDroppedPercent(); @@ -1140,7 +1279,7 @@ void Update() fps_engine = (fps_engine + CurrentTickFPS) / 2.0f; engineFPS = fps_engine.ToString("F1") + " FPS"; if (frame_drop_count > 30 && fps_engine < 45) - engineFPS += "WARNING : engine low framerate detected"; + engineFPS += "WARNING: Low engine framerate detected"; if (isZEDTracked) trackingState = ZEDTrackingState.ToString(); @@ -1151,20 +1290,17 @@ void Update() } #endif - - } public void LateUpdate() { if (IsStereoRig && VRDevice.isPresent) { - ar.LateUpdateHmdRendering(); + ar.LateUpdateHmdRendering(); //Update textures on final AR rig for output to the headset. } } #endregion - private bool isDisconnected = false; /// /// Event called when camera is disconnected /// @@ -1176,7 +1312,7 @@ void ZEDDisconnected() if (zedReady) { - Reset(); + Reset(); //Cache tracking, turn it off and turn it back on again. } } @@ -1229,7 +1365,7 @@ private GameObject CreateZEDRigDisplayer() GameObject camLeft = new GameObject("cameraLeft"); camLeft.transform.SetParent(zedRigDisplayer.transform); Camera camL = camLeft.AddComponent(); - camL.stereoTargetEye = StereoTargetEyeMask.Both; //Temporary setting to fix loading screen issue - will be set to Left once ready + camL.stereoTargetEye = StereoTargetEyeMask.Both; //Temporary setting to fix loading screen issue. camL.renderingPath = RenderingPath.Forward;//Minimal overhead camL.clearFlags = CameraClearFlags.Color; camL.backgroundColor = Color.black; @@ -1243,7 +1379,7 @@ private GameObject CreateZEDRigDisplayer() camR.renderingPath = RenderingPath.Forward;//Minimal overhead camR.clearFlags = CameraClearFlags.Color; camR.backgroundColor = Color.black; - camR.stereoTargetEye = StereoTargetEyeMask.Both; //Temporary setting to fix loading screen issue - will be set to Left once ready + camR.stereoTargetEye = StereoTargetEyeMask.Both; //Temporary setting to fix loading screen issue. camR.cullingMask = 1 << layerRightFinalScreen; camR.allowHDR = false; camR.allowMSAA = false; @@ -1253,7 +1389,7 @@ private GameObject CreateZEDRigDisplayer() //Hide camera in editor #if UNITY_EDITOR - LayerMask layerNumberBinary = (1 << layerRightFinalScreen); // This turns the layer number into the right binary number + LayerMask layerNumberBinary = (1 << layerRightFinalScreen); //Convert layer index into binary number. layerNumberBinary |= (1 << layerLeftFinalScreen); LayerMask flippedVisibleLayers = ~UnityEditor.Tools.visibleLayers; UnityEditor.Tools.visibleLayers = ~(flippedVisibleLayers | layerNumberBinary); @@ -1270,7 +1406,7 @@ private GameObject CreateZEDRigDisplayer() ar.quadRight = rightScreen.transform; - ZEDMixedRealityPlugin.OnHdmCalibChanged += CalibrationHasChanged; + ZEDMixedRealityPlugin.OnHmdCalibChanged += CalibrationHasChanged; if (UnityEngine.VR.VRDevice.isPresent) HMDDevice = UnityEngine.VR.VRDevice.model; @@ -1317,7 +1453,7 @@ void CreateMirror() #endregion /// - /// Closes out the current stream, then starts it up again. + /// Closes out the current stream, then starts it up again while maintaining tracking data. /// Used when the zed becomes unplugged, or you want to change a setting at runtime that /// requires re-initializing the camera. /// @@ -1342,9 +1478,9 @@ public void Reset() #region EventHandler /// - /// Set the overall real world brightness by setting the value triggered in the shaders + /// Changes the real-world brightness by setting the brightness value in the shaders. /// - /// New value trigged by the event + /// New value to be applied. private void CameraBrightnessChangeHandler(float newVal) { Shader.SetGlobalFloat ("_ZEDFactorAffectReal", m_cameraBrightness); @@ -1352,9 +1488,15 @@ private void CameraBrightnessChangeHandler(float newVal) /// - /// Hmd To ZED calibratio has changed ? --> Need to re-adjust Camera Left and Camera Right local position regarding ZEDRigRoot + /// Flag set to true when the HMD-to-ZED calibration file has changed during runtime. + /// Causes values from the new file to be applied during Update(). /// private bool calibrationHasChanged = false; + + /// + /// Sets the calibrationHasChanged flag to true, which causes the next Update() to + /// re-apply the HMD-to-ZED offsets. + /// private void CalibrationHasChanged() { calibrationHasChanged = true; @@ -1365,17 +1507,19 @@ private void CalibrationHasChanged() #if UNITY_EDITOR + /// + /// Handles changes to tracking or graphics settings changed from the Inspector. + /// void OnValidate() { - if (zedCamera != null) { - - if (!isTrackingEnable && enableTracking) + if (!isTrackingEnable && enableTracking) //If the user switched on tracking. { - //Enables the tracking and initializes the first position of the camera + //Enables tracking and initializes the first position of the camera. enablePoseSmoothing = enableSpatialMemory; - if (!(enableTracking = (zedCamera.EnableTracking(ref zedOrientation, ref zedPosition, enableSpatialMemory, enablePoseSmoothing, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) + if (!(enableTracking = (zedCamera.EnableTracking(ref zedOrientation, ref zedPosition, enableSpatialMemory, + enablePoseSmoothing, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) { isZEDTracked = false; throw new Exception(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_NOT_INITIALIZED)); @@ -1388,7 +1532,7 @@ void OnValidate() } - if (isTrackingEnable && !enableTracking) + if (isTrackingEnable && !enableTracking) //If the user switched off tracking. { isZEDTracked = false; lock (grabLock) @@ -1399,7 +1543,7 @@ void OnValidate() } - setRenderingSettings(); + setRenderingSettings(); //Reapplies graphics settings based on current values. } } diff --git a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs index 68a6083c..3b723a87 100644 --- a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs +++ b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs @@ -8,143 +8,249 @@ namespace sl { - /* - * Unity representation of a sl::Camera - */ - public class ZEDCamera + /// + /// Main interface between Unity and the ZED SDK. Primarily consists of extern calls to the ZED SDK wrapper .dll and + /// low-level logic to process data sent to/received from it. + /// + /// The ZEDManager component creates a ZEDCamera instance in Awake() and handles all initialization. + /// Most ZED functionality can be handled simply in Unity via ZEDManager or other high-level manager components + /// (ZEDSpatialMappingManager, ZEDPlaneDetectionManager, etc.) + /// Textures created by ZEDCamera by CreateTextureImageType() and CreateTextureMeasureType() + /// are updated automatically by the wrapper whenever a new frame is available. They represent a specific kind of + /// output, like left RGB image, or depth relative to the right sensor. As such, you never need more than one texture + /// of each kind, since it can simply be reused by all scripts that need it. Therefore, textures created in ZEDCamera + /// are indexed by their type (Image or Measure) and then by the options of each type. If a script needs a certain kind + /// of output, ZEDCamera will make a new one if it doesn't exist, but refer to the existing one otherwise. + /// + public class ZEDCamera { /// - /// Type of textures requested + /// Type of textures requested. /// public enum TYPE_VIEW { + /// + /// Image-type texture. Human-viewable but loses measurement accuracy. + /// RETRIEVE_IMAGE, + /// + /// Measure-type texture. Preserves measurement accuracy but isn't human-viewable. + /// RETRIEVE_MEASURE } /// - /// Informations of requested textures + /// Information for a requested texture. Stored in the texturesRequested list so DestroyTexture() + /// can be called with the correct arguments in DestroyAllTexture(). /// private struct TextureRequested { + /// + /// Texture type - 'image' or 'measure.' Assigned using ZEDCamera.TYPE_VIEW. + /// public int type; + /// + /// View mode (left/right eye, depth, etc.) Assigned using ZEDCommon.VIEW. + /// public int option; }; /********* Camera members ********/ - //DLL name + /// + /// DLL name, used for extern calls to the wrapper. + /// const string nameDll = "sl_unitywrapper"; - //List of all textures using the type as unique key + /// + /// List of all created textures, representing SDK output. Indexed by ints corresponding to its ZEDCamera.TYPE_VIEW + /// and its ZEDCommon.VIEW as you can't have more than one texture for each combination (nor would it be useful to). + /// private Dictionary> textures; - //List of all requested textures + /// + /// List of all requested textures. Used for destroying all textures when the camera closes. + /// private List texturesRequested; - //Width of the textures + /// + /// Width of the textures in pixels. Corresponds to the ZED's current resolution setting. + /// private int imageWidth; - - //Height of the textures + /// + /// Width of the images returned by the ZED in pixels. Corresponds to the ZED's current resolution setting. + /// + public int ImageWidth + { + get + { + return imageWidth; + } + } + /// + /// Height of the textures in pixels. Corresponds to the ZED's current resolution setting. + /// private int imageHeight; - - //ZED projection matrix + /// + /// Height of the images returned by the ZED in pixels. Corresponds to the ZED's current resolution setting. + /// + public int ImageHeight + { + get + { + return imageHeight; + } + } + /// + /// Projection matrix corresponding to the ZED's camera traits. Useful for lining up virtual cameras with the ZED image. + /// private Matrix4x4 projection = new Matrix4x4(); + /// + /// Projection matrix corresponding to the ZED's camera traits. Useful for lining up virtual cameras with the ZED image. + /// + public Matrix4x4 Projection + { + get + { + return projection; + } + } - //Singleton of ZEDCamera + /// + /// Current ZED instance. Used for Singleton implementation. + /// private static ZEDCamera instance = null; - //True if the SDK is installed + /// + /// True if the ZED SDK is installed. + /// private static bool pluginIsReady = true; - //Mutex for threaded rendering + /// + /// Mutex for threaded rendering. + /// private static object _lock = new object(); - //The current resolution + /// + /// Current ZED resolution setting. Set at initialization. + /// private RESOLUTION currentResolution; - //Callback for c++ debug, should not be used in C# + /// + /// Callback for c++ debugging. Should not be used in C#. + /// private delegate void DebugCallback(string message); - //HD720 default FPS - private uint fpsMax = 60; + /// + /// Desired FPS from the ZED camera. This is the maximum FPS for the ZED's current + /// resolution unless a lower setting was specified in Init(). + /// Maximum values are bound by the ZED's output, not system performance. + /// + private uint fpsMax = 60; //Defaults to HD720 resolution's output. + /// + /// Desired FPS from the ZED camera. This is the maximum FPS for the ZED's current + /// resolution unless a lower setting was specified in Init(). + /// Maximum values are bound by the ZED's output, not system performance. + /// + public float GetRequestedCameraFPS() + { + return fpsMax; + } + /// + /// Holds camera settings like brightness/contrast, gain/exposure, etc. + /// private ZEDCameraSettingsManager cameraSettingsManager = new ZEDCameraSettingsManager(); - - // Baseline of the camera + /// + /// Camera's stereo baseline (distance between the cameras). Extracted from calibration files. + /// private float baseline = 0.0f; + /// + /// Camera's stereo baseline (distance between the cameras). Extracted from calibration files. + /// public float Baseline { get { return baseline; } } /// - /// Current field of view + /// ZED's current horizontal field of view in degrees. /// private float fov_H = 0.0f; - private float fov_V = 0.0f; - /// - /// Current field of view + /// ZED's current vertical field of view in degrees. + /// + private float fov_V = 0.0f; + /// + /// ZED's current horizontal field of view in degrees. /// public float HorizontalFieldOfView { get { return fov_H; } } - - public float VerticalFieldOfView + /// + /// ZED's current vertical field of view in degrees. + /// + public float VerticalFieldOfView { get { return fov_V; } } /// - /// Information in cache + /// Stereo parameters for current ZED camera prior to rectification (distorted). /// private CalibrationParameters calibrationParametersRaw; + /// + /// Stereo parameters for current ZED camera after rectification (undistorted). + /// private CalibrationParameters calibrationParametersRectified; - /// - /// Camera Model + /// Camera model - ZED or ZED Mini. /// private sl.MODEL cameraModel; /// - /// Camera is opened or not + /// Whether the camera has been successfully initialized. /// private bool cameraReady = false; /// - /// Information in cache, call GetInformation to update + /// Stereo parameters for current ZED camera prior to rectification (distorted). /// public CalibrationParameters CalibrationParametersRaw { get { return calibrationParametersRaw; } } - /// - /// Information in cache, call GetInformation to update - /// + /// + /// Stereo parameters for current ZED camera after rectification (undistorted). + /// public CalibrationParameters CalibrationParametersRectified { get { return calibrationParametersRectified; } } - /// - /// Information in cache, call GetInformation to update - /// - public sl.MODEL CameraModel + /// + /// Camera model - ZED or ZED Mini. + /// + public sl.MODEL CameraModel { get { return cameraModel; } } - - public bool IsCameraReady + /// + /// Whether the camera has been successfully initialized. + /// + public bool IsCameraReady { get { return cameraReady; } } - + /// + /// Whether the current device (ZED or ZED Mini) should be used for pass-through AR. + /// True if using ZED Mini, false if using ZED. Note: the plugin will allow using the original ZED + /// for pass-through but it will feel quite uncomfortable due to the baseline. public bool IsHmdCompatible { get { return cameraModel == sl.MODEL.ZED_M; } } /// - /// DLL needed to run the exe + /// List of DLLs needed to run the plugin. /// static private string[] dependenciesNeeded = { @@ -153,28 +259,34 @@ public bool IsHmdCompatible "sl_input64.dll" }; - + /// + /// Layer that only the ZED is able to see. Used in ZEDSteamVRControllerManager for 'clone' controllers. + /// const int tagZEDCamera = 20; /// - /// Layer only the ZED is able to see + /// Layer that only the ZED is able to see. Used in ZEDSteamVRControllerManager for 'clone' controllers. /// public static int Tag { get { return tagZEDCamera; } } /// - /// Layer only the other cameras apart the ZED are able to see + /// Layer that the ZED can't see, but overlay cameras created by ZEDMeshRenderer and ZEDPlaneRenderer can. /// const int tagOneObject = 12; + /// + /// Layer that the ZED can't see, but overlay cameras created by ZEDMeshRenderer and ZEDPlaneRenderer can. + /// public static int TagOneObject { get { return tagOneObject; } } - /// - /// Cuurent Plugin Version - /// - public static readonly System.Version PluginVersion = new System.Version(2, 5, 0); + #region DLL Calls + /// + /// Cuurent Plugin Version. + /// + public static readonly System.Version PluginVersion = new System.Version(2, 6, 0); /******** DLL members ***********/ @@ -186,7 +298,7 @@ public static int TagOneObject /* - * Utils function + * Utils function. */ [DllImport(nameDll, EntryPoint = "dllz_find_usb_device")] private static extern bool dllz_find_usb_device(USB_DEVICE dev); @@ -199,31 +311,31 @@ public static int TagOneObject /* - * Opening function (Open camera and create textures) + * Opening function (Opens camera and creates textures). */ [DllImport(nameDll, EntryPoint = "dllz_open")] - private static extern int dllz_open(ref dll_initParameters parameters, System.Text.StringBuilder svoPath, System.Text.StringBuilder output); + private static extern int dllz_open(ref dll_initParameters parameters, System.Text.StringBuilder svoPath, System.Text.StringBuilder output,System.Text.StringBuilder opt_settings_path); /* - * Close function + * Close function. */ [DllImport(nameDll, EntryPoint = "dllz_close")] private static extern void dllz_close(); /* - * Grab function - */ + * Grab function. + */ [DllImport(nameDll, EntryPoint = "dllz_grab")] private static extern int dllz_grab(ref sl.RuntimeParameters runtimeParameters); /* - * Recording functions + * Recording functions. */ [DllImport(nameDll, EntryPoint = "dllz_enable_recording")] private static extern int dllz_enable_recording(byte[] video_filename, int compresssionMode); @@ -236,7 +348,7 @@ public static int TagOneObject /* - * Texturing functions + * Texturing functions. */ [DllImport(nameDll, EntryPoint = "dllz_retrieve_textures")] private static extern void dllz_retrieve_textures(); @@ -266,8 +378,9 @@ public static int TagOneObject [DllImport(nameDll, EntryPoint = "dllz_get_copy_mat_texture_measure_type")] private static extern IntPtr dllz_get_copy_mat_texture_measure_type(int option); + /* - * Self-calibration function + * Self-calibration functions. */ [DllImport(nameDll, EntryPoint = "dllz_reset_self_calibration")] private static extern void dllz_reset_self_calibration(); @@ -277,7 +390,7 @@ public static int TagOneObject /* - * Camera control functions + * Camera control functions. */ @@ -308,7 +421,6 @@ public static int TagOneObject [DllImport(nameDll, EntryPoint = "dllz_get_camera_imu_transform")] private static extern void dllz_get_camera_imu_transform(ulong timeStamp, bool useLatency,out Vector3 translation, out Quaternion rotation); - [DllImport(nameDll, EntryPoint = "dllz_is_zed_connected")] private static extern int dllz_is_zed_connected(); @@ -328,7 +440,7 @@ public static int TagOneObject private static extern float dllz_get_frame_dropped_percent(); /* - * SVO control functions + * SVO control functions. */ [DllImport(nameDll, EntryPoint = "dllz_set_svo_position")] @@ -342,7 +454,7 @@ public static int TagOneObject /* - * Depth Sensing utils functions + * Depth Sensing utils functions. */ [DllImport(nameDll, EntryPoint = "dllz_set_confidence_threshold")] private static extern void dllz_set_confidence_threshold(int threshold); @@ -373,7 +485,7 @@ public static int TagOneObject /* - * Motion Tracking functions + * Motion Tracking functions. */ [DllImport(nameDll, EntryPoint = "dllz_enable_tracking")] private static extern int dllz_enable_tracking(ref Quaternion quat, ref Vector3 vec, bool enableSpatialMemory = false,bool enablePoseSmoothing = false, System.Text.StringBuilder aeraFilePath = null); @@ -402,7 +514,6 @@ public static int TagOneObject [DllImport(nameDll, EntryPoint = "dllz_reset_tracking_with_offset")] private static extern int dllz_reset_tracking_with_offset(Quaternion rotation, Vector3 translation, Quaternion offsetQuaternion, Vector3 offsetTranslation); - [DllImport(nameDll, EntryPoint = "dllz_set_imu_prior_orientation")] private static extern int dllz_set_imu_prior_orientation(Quaternion rotation); @@ -412,11 +523,11 @@ public static int TagOneObject [DllImport(nameDll, EntryPoint = "dllz_get_internal_imu_data")] private static extern int dllz_get_internal_imu_data(ref IMUData imuData, int reference_time); - [DllImport(nameDll, EntryPoint = "dllz_get_area_export_state")] private static extern int dllz_get_area_export_state(); + /* - * Spatial Mapping functions + * Spatial Mapping functions. */ [DllImport(nameDll, EntryPoint = "dllz_enable_spatial_mapping")] private static extern int dllz_enable_spatial_mapping(float resolution_meter, float max_range_meter, int saveTexture); @@ -504,6 +615,8 @@ public static int TagOneObject [DllImport(nameDll, EntryPoint = "dllz_retrieve_image")] private static extern int dllz_retrieve_image(System.IntPtr ptr, int type, int mem, sl.Resolution resolution); + #endregion + public static void ComputeOffset(float[] A, float[] B, int nbVectors, ref Quaternion rotation, ref Vector3 translation) { float[] C = new float[16]; @@ -522,10 +635,10 @@ public static void ComputeOffset(float[] A, float[] B, int nbVectors, ref Quater } /// - /// Return a string from a pointer to char + /// Return a string from a pointer to a char. Used in GetSDKVersion(). /// - /// - /// the string + /// Pointer to a char. + /// The char as a string. private static string PtrToStringUtf8(IntPtr ptr) { if (ptr == IntPtr.Zero) @@ -545,7 +658,7 @@ private static string PtrToStringUtf8(IntPtr ptr) } /// - /// Display a console message from c++ + /// Displays a console message. Used to display C++ SDK messages in Unity's console. /// /// private static void DebugMethod(string message) @@ -554,10 +667,10 @@ private static void DebugMethod(string message) } /// - /// Convert a pointer to char to an array of bytes + /// Convert a pointer to a char into an array of bytes. Used to send file names to SDK for SVO recording. /// - /// - /// The array + /// Pointer to a char. + /// The array. private static byte[] StringUtf8ToByte(string str) { byte[] array = System.Text.Encoding.ASCII.GetBytes(str); @@ -565,7 +678,7 @@ private static byte[] StringUtf8ToByte(string str) } /// - /// Get the max fps for each resolution, higher fps will cause lower GPU performance + /// Gets the max FPS for each resolution setting. Higher FPS will cause lower GPU performance. /// /// /// The resolution @@ -579,10 +692,10 @@ static private uint GetFpsForResolution(RESOLUTION reso) } /// - /// Get a quaternion from a matrix with a minimum size of 3x3 + /// Get a quaternion from a matrix with a minimum size of 3x3. /// - /// The matrix - /// A quaternion which contains the rotation + /// The matrix. + /// A quaternion which contains the matrix's rotation. public static Quaternion Matrix4ToQuaternion(Matrix4x4 m) { Quaternion q = new Quaternion(); @@ -597,7 +710,7 @@ public static Quaternion Matrix4ToQuaternion(Matrix4x4 m) } /// - /// Rigid transform + /// Performs a rigid transform. /// /// /// @@ -609,22 +722,22 @@ public static void TransformPose(ref Quaternion quaternion, ref Vector3 translat } /// - /// Check if the plugin is available + /// Checks that the ZED plugin's dependencies are installed. /// public static bool CheckPlugin() { pluginIsReady = false; - string env = Environment.GetEnvironmentVariable("ZED_SDK_ROOT_DIR"); - if (env != null) + string env = Environment.GetEnvironmentVariable("ZED_SDK_ROOT_DIR"); + if (env != null) //Found path to the ZED SDK in PC's environmental variables. { - bool error = CheckDependencies(System.IO.Directory.GetFiles(env + "\\bin")); + bool error = CheckDependencies(System.IO.Directory.GetFiles(env + "\\bin")); //Make sure ZED dlls exist and work. if (error) { - Debug.LogError (ZEDLogMessage.Error2Str (ZEDLogMessage.ERROR.SDK_NOT_INSTALLED)); + Debug.LogError (ZEDLogMessage.Error2Str (ZEDLogMessage.ERROR.SDK_NOT_INSTALLED)); //Print that SDK isn't installed. return false; - } else { + } else { //Found DLLs in ZED install directory. try { - if (dllz_check_plugin (PluginVersion.Major, PluginVersion.Minor) != 0) { + if (dllz_check_plugin (PluginVersion.Major, PluginVersion.Minor) != 0) { //0 = installed SDK is compatible with plugin. 1 otherwise. Debug.LogError (ZEDLogMessage.Error2Str (ZEDLogMessage.ERROR.SDK_DEPENDENCIES_ISSUE)); return false; } @@ -636,23 +749,22 @@ public static bool CheckPlugin() } } } - else + else //Couldn't find the ZED SDK in the computer's environmental variables. { Debug.LogError(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_NOT_INSTALLED)); return false; } - pluginIsReady = true; return true; } /// - /// Checks the USB device of "brand" Type is connected. + /// Checks if the USB device of a 'brand' type is connected. Used to check if a VR headset are connected + /// for display in ZEDManager's Inspector. /// - /// This function is static and can be called anytime - /// true, if USB device connected was found, false otherwise. - /// Type. + /// True, if USB device connected was found, false otherwise. + /// Type. public static bool CheckUSBDeviceConnected(USB_DEVICE Type) { if (dllz_find_usb_device (Type)) @@ -662,10 +774,10 @@ public static bool CheckUSBDeviceConnected(USB_DEVICE Type) } /// - /// Checks if all the dlls ara available and try to call a dummy function from the DLL + /// Checks if all the required DLLs are available and tries calling a dummy function from each one. /// - /// - /// + /// All files in a specified directory. + /// True if the dependencies were not found. False if they were all found. static private bool CheckDependencies(string[] filesFound) { bool isASDKPb = false; @@ -695,9 +807,9 @@ static private bool CheckDependencies(string[] filesFound) } /// - /// Gets an instance of the ZEDCamera + /// Singleton implementation. Gets the instance of the ZEDCamera, creating a new one if one doesn't exist. /// - /// The instance + /// The ZEDCamera instance. public static ZEDCamera GetInstance() { lock (_lock) @@ -713,7 +825,7 @@ public static ZEDCamera GetInstance() } /// - /// Private constructor + /// Private constructor. Initializes lists to hold references to textures and texture requests. /// private ZEDCamera() { @@ -723,13 +835,11 @@ private ZEDCamera() } /// - /// Create a camera in live mode + /// Create a camera in Live mode (input comes from a connected ZED device, not SVO playback). /// - /// - /// + /// True to create detailed log file of SDK calls at the cost of performance. public void CreateCamera(bool verbose) { - string infoSystem = SystemInfo.graphicsDeviceType.ToString().ToUpper(); if (!infoSystem.Equals("DIRECT3D11") && !infoSystem.Equals("OPENGLCORE")) { @@ -739,47 +849,98 @@ public void CreateCamera(bool verbose) } /// - /// Close the camera and delete all textures - /// Once destroyed, you need to recreate a camera to restart again + /// Closes the camera and deletes all textures. + /// Once destroyed, you need to recreate a camera instance to restart again. /// public void Destroy() { - if (instance != null) { cameraReady = false; - dllz_close (); - DestroyAllTexture (); + dllz_close(); + DestroyAllTexture(); instance = null; } } - - + /// + /// DLL-friendly version of InitParameters (found in ZEDCommon.cs). + /// [StructLayout(LayoutKind.Sequential)] public struct dll_initParameters { + /// + /// Resolution the ZED will be set to. + /// public sl.RESOLUTION resolution; + /// + /// Desired camera FPS. Max is set by resolution. + /// public int cameraFps; + /// + /// ID for identifying which of multiple connected ZEDs to use. + /// NOT CURRENTLY SUPPORTED IN UNITY. + /// public int cameraLinuxID; + /// + /// True to skip dropped frames during SVO playback. + /// [MarshalAs(UnmanagedType.U1)] public bool svoRealTimeMode; + /// + /// Coordinate unit for all measurements (depth, tracking, etc.). Meters are recommended for Unity. + /// public UNIT coordinateUnit; + /// + /// Defines order and direction of coordinate system axes. Unity uses left-handed, Y up, so this setting is recommended. + /// public COORDINATE_SYSTEM coordinateSystem; + /// + /// Quality level of depth calculations. Higher settings improve accuracy but cost performance. + /// public sl.DEPTH_MODE depthMode; + /// + /// Minimum distance from the camera from which depth will be computed, in the defined coordinateUnit. + /// public float depthMinimumDistance; + /// + /// True to flip images horizontally. + /// [MarshalAs(UnmanagedType.U1)] public bool cameraImageFlip; + /// + /// True if depth relative to the right sensor should be computed. + /// [MarshalAs(UnmanagedType.U1)] public bool enableRightSideMeasure; + /// + /// True to disable self-calibration, using unoptimized optional calibration parameters. + /// False is recommended for optimized calibration. + /// [MarshalAs(UnmanagedType.U1)] public bool cameraDisableSelfCalib; + /// + /// Set the number of buffers for the internal buffer process. LINUX ONLY - NOT CURRENTLY USED IN UNITY PLUGIN. + /// public int cameraBufferCountLinux; + /// + /// True for the SDK to provide text feedback. + /// [MarshalAs(UnmanagedType.U1)] public bool sdkVerbose; + /// + /// ID of the graphics card on which the ZED's computations will be performed. + /// public int sdkGPUId; + /// + /// True to stabilize the depth map. Recommended. + /// [MarshalAs(UnmanagedType.U1)] public bool depthStabilization; + /// + /// Copy constructor. Takes values from Unity-suited InitParameters class. + /// + /// public dll_initParameters(InitParameters init) { resolution = init.resolution; @@ -802,19 +963,15 @@ public dll_initParameters(InitParameters init) /// - /// The Init function must be called after the instantiation. The function checks if the ZED camera is plugged and opens it, initialize the projection matix and command buffers to update textures + /// Checks if the ZED camera is plugged in, opens it, and initializes the projection matix and command buffers for updating textures. /// - /// defines the quality of the depth map, affects the level of details and also the computation time. - /// specify the minimum depth information that will be computed, in the unit you previously define. - /// if set to true, it will disable self-calibration and take the initial calibration parameters without optimizing them - /// ERROR_CODE : The error code gives information about the - /// internal process, if SUCCESS is returned, the camera is ready to use. - /// Every other code indicates an error and the program should be stopped. - /// - /// For more details see sl::zed::ERRCODE. + /// Class with all initialization settings. + /// A newly-instantiated InitParameters will have recommended default values. + /// ERROR_CODE: The error code gives information about the internal connection process. + /// If SUCCESS is returned, the camera is ready to use. Every other code indicates an error. public ERROR_CODE Init(ref InitParameters initParameters) { - + //Update values with what we're about to pass to the camera. currentResolution = initParameters.resolution; fpsMax = GetFpsForResolution(currentResolution); if (initParameters.cameraFPS == 0) @@ -822,12 +979,12 @@ public ERROR_CODE Init(ref InitParameters initParameters) initParameters.cameraFPS = (int)fpsMax; } - dll_initParameters initP = new dll_initParameters(initParameters); - initP.coordinateSystem = COORDINATE_SYSTEM.LEFT_HANDED_Y_UP; - - initParameters.sdkVerboseLogFile = "D:/tmp/sdl_log.txt"; - int v = dllz_open(ref initP, new System.Text.StringBuilder(initParameters.pathSVO, initParameters.pathSVO.Length), - new System.Text.StringBuilder(initParameters.sdkVerboseLogFile, initParameters.sdkVerboseLogFile.Length)); + dll_initParameters initP = new dll_initParameters(initParameters); //DLL-friendly version of InitParameters. + initP.coordinateSystem = COORDINATE_SYSTEM.LEFT_HANDED_Y_UP; //Left-hand, Y-up is Unity's coordinate system, so we match that. + int v = dllz_open(ref initP, + new System.Text.StringBuilder(initParameters.pathSVO, initParameters.pathSVO.Length), + new System.Text.StringBuilder(initParameters.sdkVerboseLogFile, initParameters.sdkVerboseLogFile.Length), + new System.Text.StringBuilder(initParameters.optionalSettingsPath, initParameters.optionalSettingsPath.Length)); if ((ERROR_CODE)v != ERROR_CODE.SUCCESS) { @@ -835,6 +992,7 @@ public ERROR_CODE Init(ref InitParameters initParameters) return (ERROR_CODE)v; } + //Set more values if the initialization was successful. imageWidth = dllz_get_width(); imageHeight = dllz_get_height(); @@ -851,7 +1009,8 @@ public ERROR_CODE Init(ref InitParameters initParameters) /// - /// Fill the projection matrix with the parameters of the ZED, needs to be called only once. This projection matrix is off center. + /// Fills the projection matrix with the parameters of the ZED. Needs to be called only once. + /// This projection matrix is off-center. /// /// /// @@ -864,22 +1023,21 @@ public void FillProjectionMatrix(float zFar = 500, float zNear = 0.1f) float f_imageWidth = (float)ImageWidth; float f_imageHeight = (float)ImageHeight; - - //Debug.Log(parameters.leftCam.cx); - projection[0, 0] = 1.0f / Mathf.Tan(fovx * 0.5f); + //Manually construct the matrix based on initialization/calibration values. + projection[0, 0] = 1.0f / Mathf.Tan(fovx * 0.5f); //Horizontal FoV. projection[0, 1] = 0; - projection[0, 2] = 2.0f * ((f_imageWidth - 1.0f * parameters.leftCam.cx) / f_imageWidth) - 1.0f; + projection[0, 2] = 2.0f * ((f_imageWidth - 1.0f * parameters.leftCam.cx) / f_imageWidth) - 1.0f; //Horizontal offset. projection[0, 3] = 0; projection[1, 0] = 0; - projection[1, 1] = 1.0f / Mathf.Tan(fovy * 0.5f); - projection[1, 2] = -(2.0f * ((f_imageHeight - 1.0f * parameters.leftCam.cy) / f_imageHeight) - 1.0f); + projection[1, 1] = 1.0f / Mathf.Tan(fovy * 0.5f); //Vertical FoV. + projection[1, 2] = -(2.0f * ((f_imageHeight - 1.0f * parameters.leftCam.cy) / f_imageHeight) - 1.0f); //Vertical offset. projection[1, 3] = 0; projection[2, 0] = 0; projection[2, 1] = 0; - projection[2, 2] = -(zFar + zNear) / (zFar - zNear); - projection[2, 3] = -(2.0f * zFar * zNear) / (zFar - zNear); + projection[2, 2] = -(zFar + zNear) / (zFar - zNear); //Near and far planes. + projection[2, 3] = -(2.0f * zFar * zNear) / (zFar - zNear); //Near and far planes. projection[3, 0] = 0; projection[3, 1] = 0; @@ -889,11 +1047,11 @@ public void FillProjectionMatrix(float zFar = 500, float zNear = 0.1f) } /// - /// Grab a new image, rectifies it and computes the - /// disparity map and optionally the depth map. - /// The grabbing function is typically called in the main loop. - /// - /// defines the type of disparity map, more info : SENSING_MODE definition + /// Grabs a new image, rectifies it, and computes the disparity map and (optionally) the depth map. + /// The grabbing function is typically called in the main loop in a separate thread. + /// For more info, read about the SDK function it calls: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/classsl_1_1Camera.html#afa3678a18dd574e162977e97d7cbf67b + /// Struct holding all grab parameters. /// the function returns false if no problem was encountered, /// true otherwise. public sl.ERROR_CODE Grab(ref sl.RuntimeParameters runtimeParameters) @@ -901,35 +1059,30 @@ public sl.ERROR_CODE Grab(ref sl.RuntimeParameters runtimeParameters) return (sl.ERROR_CODE)dllz_grab(ref runtimeParameters); } - /// - /// The reset function can be called at any time AFTER the Init function has been called. - /// It will reset and calculate again correction for misalignment, convergence and color mismatch. - /// It can be called after changing camera parameters without needing to restart your executable. + /// The reset function can be called at any time AFTER the Init function has been called. + /// It will reset and recalculate to correct for misalignment, convergence and color mismatch. + /// It can be called after changing camera parameters without needing to restart your executable. /// - /// - /// ERRCODE : error boolean value : the function returns false if no problem was encountered, - /// true otherwise. - /// if no problem was encountered, the camera will use new parameters. Otherwise, it will be the old ones - /// public void ResetSelfCalibration() { dllz_reset_self_calibration(); } /// - /// Creates a file for recording the current frames. - /// - /// can be a *.svo file or a *.avi file (detected by the suffix name provided) - /// can be one of the sl.SVO_COMPRESSION_MODE enum - /// an sl.ERRCODE that defines if file was successfully created and can be filled with images + /// Creates a file for recording the ZED's output into a .SVO or .AVI video. + /// An SVO is Stereolabs' own format designed for the ZED. It holds the video feed with timestamps + /// as well as info about the camera used to record it. + /// Filename. Whether it ends with .svo or .avi defines its file type. + /// How much compression to use + /// An ERROR_CODE that defines if the file was successfully created and can be filled with images. public ERROR_CODE EnableRecording(string videoFileName, SVO_COMPRESSION_MODE compressionMode = SVO_COMPRESSION_MODE.LOSSLESS_BASED) { return (ERROR_CODE)dllz_enable_recording(StringUtf8ToByte(videoFileName), (int)compressionMode); } /// - /// Record the images, EnableRecording needs to be called before. + /// Begins record the images to an SVO or AVI. EnableRecording() needs to be called first. /// public Recording_state Record() { @@ -939,19 +1092,18 @@ public Recording_state Record() } /// - /// Stops the recording and closes the file. + /// Stops recording to an SVO/AVI, if applicable, and closes the file. /// - /// public bool DisableRecording() { return dllz_disable_recording(); } /// - /// Set a new frame rate for the camera, or the closest available frame rate. + /// Sets a new target frame rate for the camera. If it's not possible with the current resolution, + /// the SDK will target the closest possible frame rate instead. /// - /// - /// + /// New target FPS. public void SetCameraFPS(int fps) { if (GetFpsForResolution(currentResolution) >= fps) @@ -963,10 +1115,9 @@ public void SetCameraFPS(int fps) } /// - /// Sets the position of the SVO file to a desired frame. + /// Sets the position of the SVO file currently being read to a desired frame. /// - /// the number of the desired frame to be decoded. - /// + /// Index of the desired frame to be decoded. public void SetSVOPosition(int frame) { dllz_set_svo_position(frame); @@ -974,64 +1125,65 @@ public void SetSVOPosition(int frame) /// /// Gets the current confidence threshold value for the disparity map (and by extension the depth map). + /// Values below the given threshold are removed from the depth map. /// - /// current filtering value between 0 and 100. + /// Filtering value between 0 and 100. public int GetConfidenceThreshold() { return dllz_get_confidence_threshold(); } /// - /// Get the time stamp at the time the frame has been extracted from USB stream. (should be called after a grab()) + /// Gets the timestamp at the time the latest grabbed frame was extracted from the USB stream. + /// This is the closest timestamp you can get from when the image was taken. Must be called after calling grab(). /// - /// Current time stamp in ns. -1 is not available(SVO file without compression). - /// Note that new SVO file from SDK 1.0.0 (with compression) contains the camera time stamp for each frame. + /// Current timestamp in nanoseconds. -1 means it's is not available, such as with an .SVO file without compression. public ulong GetCameraTimeStamp() { return dllz_get_camera_timestamp(); } /// - /// Get the current time stamp at the time the function is called. Can be compared to the camera time stamp for synchronization. - /// Use this function to compare the current time stamp and the camera time stamp, since they have the same reference (Computer start time). + /// Gets the current timestamp at the time the function is called. Can be compared to the camera timestamp + /// for synchronization, since they have the same reference (the computer's start time). /// - /// The timestamp + /// The timestamp in nanoseconds. public ulong GetCurrentTimeStamp() { return dllz_get_current_timestamp(); } /// - /// Last time stamp from image update, (based on the computer time stamp) + /// Timestamp from the most recent image update. Based on the computer's start time. /// - /// The timestamp + /// The timestamp in nanoseconds. public ulong GetImageUpdaterTimeStamp() { return dllz_get_image_updater_time_stamp(); } /// - /// Get the current position of the SVO in the record + /// Get the current position of the SVO being recorded to. /// - /// The position + /// Index of the frame being recorded to. public int GetSVOPosition() { return dllz_get_svo_position(); } /// - /// Get the number of frames in the SVO file. + /// Gets the total number of frames in the loaded SVO file. /// - /// SVO Style Only : the total number of frames in the SVO file(-1 if the SDK is not reading a SVO) + /// Total frames in the SVO file. Returns -1 if the SDK is not reading an SVO. public int GetSVONumberOfFrames() { return dllz_get_svo_number_of_frames(); } /// - /// Get the closest measurable distance by the camera, according to the camera and the depth map parameters. + /// Gets the closest measurable distance by the camera, according to the camera type and depth map parameters. /// - /// The closest depth + /// The nearest possible depth value. public float GetDepthMinRangeValue() { return dllz_get_depth_min_range_value(); @@ -1049,12 +1201,12 @@ public float GetDepthMaxRangeValue() /// /// Initialize and Start the tracking functions /// - /// rotation used as initial world transform.By default it should be identity. + /// rotation used as initial world transform. By default it should be identity. /// translation used as initial world transform. By default it should be identity. /// (optional) define if spatial memory is enable or not. /// (optional) file of spatial memory file that has to be loaded to relocate in the scene. /// - public sl.ERROR_CODE EnableTracking(ref Quaternion quat, ref Vector3 vec, bool enableSpatialMemory = true,bool enablePoseSmoothing = false, string areaFilePath = "") + public sl.ERROR_CODE EnableTracking(ref Quaternion quat, ref Vector3 vec, bool enableSpatialMemory = true, bool enablePoseSmoothing = false, string areaFilePath = "") { sl.ERROR_CODE trackingStatus = sl.ERROR_CODE.CAMERA_NOT_DETECTED; trackingStatus = (sl.ERROR_CODE)dllz_enable_tracking (ref quat, ref vec, enableSpatialMemory, enablePoseSmoothing, new System.Text.StringBuilder (areaFilePath, areaFilePath.Length)); @@ -1119,10 +1271,16 @@ private void RegisterTexture(Texture2D m_Texture, int type, int mode) } /// - /// Create or retrieve a texture of type Image (from Camera::retrieveImage()). Create the texture if needed. + /// Creates or retrieves a texture of type Image. Will be updated each frame automatically. + /// Image type textures are human-viewable, but have less accuracy than measure types. /// - /// - /// + /// + /// Note that the new texture will exist on the GPU, so accessing from the CPU will result in an empty image. To get images + /// with the CPU, use RetrieveImage() instead and specify CPU memory in the arguments. + /// + /// What the image shows (left RGB image, right depth image, normal map, etc.) + /// /// Resolution of the image. Should correspond to ZED's current resolution. + /// Texture2D that will update each frame with the ZED SDK's output. public Texture2D CreateTextureImageType(VIEW mode, Resolution resolution = new Resolution()) { if (HasTexture((int)TYPE_VIEW.RETRIEVE_IMAGE, (int)mode)) @@ -1134,7 +1292,7 @@ private void RegisterTexture(Texture2D m_Texture, int type, int mode) int width = ImageWidth; int height = imageHeight; - if (!((uint)resolution.width == 0 && (uint)resolution.height == 0)) + if (!((uint)resolution.width == 0 && (uint)resolution.height == 0)) //Handles if Resolution arg was empty, as in the default. { width = (int)resolution.width; height = (int)resolution.height; @@ -1147,7 +1305,7 @@ private void RegisterTexture(Texture2D m_Texture, int type, int mode) } else if (mode == VIEW.SIDE_BY_SIDE) { - m_Texture = new Texture2D(width * 2, height, TextureFormat.RGBA32, false); + m_Texture = new Texture2D(width * 2, height, TextureFormat.RGBA32, false); //Needs to be twice as wide for SBS because there are two images. } else { @@ -1162,22 +1320,28 @@ private void RegisterTexture(Texture2D m_Texture, int type, int mode) int error = dllz_register_texture_image_type((int)mode, idTexture, resolution); if (error != 0) { - throw new Exception("Error Cuda " + error + " if the problem appears again, please contact the support"); + throw new Exception("CUDA error:" + error + " if the problem appears again, please contact Stereolabs support."); } - if (!textures.ContainsKey((int)TYPE_VIEW.RETRIEVE_IMAGE)) + if (!textures.ContainsKey((int)TYPE_VIEW.RETRIEVE_IMAGE)) { textures.Add((int)TYPE_VIEW.RETRIEVE_IMAGE, new Dictionary()); } - RegisterTexture(m_Texture, (int)TYPE_VIEW.RETRIEVE_IMAGE, (int)mode); + RegisterTexture(m_Texture, (int)TYPE_VIEW.RETRIEVE_IMAGE, (int)mode); //Save so you don't make a duplicate if another script needs the texture. return m_Texture; } /// - /// Create or retrieve a texture of type Measure (from Camera::retrieveMeasure()). Create the texture if needed. + /// Creates or retrievse a texture of type Measure. Will be updated each frame automatically. + /// Measure types are not human-viewable, but don't lose any accuracy. /// - /// - /// + /// + /// Note that the new texture will exist on the GPU, so accessing from the CPU will result in an empty image. To get images + /// with the CPU, use RetrieveMeasure() instead and specify CPU memory in the arguments. + /// + /// What the image shows (disparity, depth, confidence, etc.) + /// Resolution of the image. Should correspond to ZED's current resolution. + /// Texture2D that will update each frame with the ZED SDK's output. public Texture2D CreateTextureMeasureType(MEASURE mode, Resolution resolution = new Resolution()) { if (HasTexture((int)TYPE_VIEW.RETRIEVE_MEASURE, (int)mode)) @@ -1195,6 +1359,7 @@ private void RegisterTexture(Texture2D m_Texture, int type, int mode) width = (int)resolution.width; height = (int)resolution.height; } + //Handle the mode options. if (mode == MEASURE.XYZ || mode == MEASURE.XYZABGR || mode == MEASURE.XYZARGB || mode == MEASURE.XYZBGRA || mode == MEASURE.XYZRGBA || mode == MEASURE.NORMALS || mode == MEASURE.XYZ_RIGHT || mode == MEASURE.XYZABGR_RIGHT || mode == MEASURE.XYZARGB_RIGHT || mode == MEASURE.XYZBGRA_RIGHT || mode == MEASURE.XYZRGBA_RIGHT || mode == MEASURE.NORMALS_RIGHT) { @@ -1225,23 +1390,22 @@ private void RegisterTexture(Texture2D m_Texture, int type, int mode) if (error != 0) { - throw new Exception("Error Cuda " + error + " if the problem appears again, please contact the support"); + throw new Exception("CUDA error:" + error + " if the problem appears again, please contact Stereolabs support."); } if (!textures.ContainsKey((int)TYPE_VIEW.RETRIEVE_MEASURE)) { textures.Add((int)TYPE_VIEW.RETRIEVE_MEASURE, new Dictionary()); } - RegisterTexture(m_Texture, (int)TYPE_VIEW.RETRIEVE_MEASURE, (int)mode); + RegisterTexture(m_Texture, (int)TYPE_VIEW.RETRIEVE_MEASURE, (int)mode); //Save to avoid duplicates if texture type is needed elsewhere. return m_Texture; } /// - /// Unregister a texture of type image, this texture will be destroyed and not be updated anymore + /// Unregisters a texture of type Image. The texture will be destroyed and will no longer be updated each frame. /// - /// - /// + /// What the image was showing (left RGB image, right depth image, normal map, etc.) public bool UnregisterTextureImageType(sl.VIEW view) { DestroyTextureImageType((int)view); @@ -1249,10 +1413,9 @@ public bool UnregisterTextureImageType(sl.VIEW view) } /// - /// Unregister a texture of type measure, this texture will be destroyed and not be updated anymore + /// Unregisters a texture of type Measure, The texture will be destroyed and will no longer be updated each frame. /// - /// - /// + /// What the measure was showing (disparity, depth, confidence, etc.) public bool UnregisterTextureMeasureType(sl.MEASURE measure) { DestroyTextureMeasureType((int)measure); @@ -1260,30 +1423,30 @@ public bool UnregisterTextureMeasureType(sl.MEASURE measure) } /// - /// Copy a Texture of type image to a Mat, this function should be called after a grab and a updateTexture + /// Copies a Texture of type Image into a ZEDMat. This function should be called after a Grab() and an UpdateTextures(). /// - /// - /// + /// View type (left rgb, right depth, etc.) + /// New ZEDMat for an image texture of the selected view type. public ZEDMat RequestCopyMatFromTextureImageType(sl.VIEW view) { return new ZEDMat(dllz_get_copy_mat_texture_image_type((int)view)); } /// - /// Copy a Texture of type measure to a Mat, this function should be called after a grab and a updateTexture + /// Copies a texture of type Measure into a ZEDMat. This function should be called after a Grab() and an UpdateTextures(). /// - /// - /// + /// Measure type (depth, disparity, confidence, etc.) + /// New ZEDMat for a measure texture of the selected measure type. public ZEDMat RequestCopyMatFromTextureMeasureType(sl.MEASURE measure) { return new ZEDMat(dllz_get_copy_mat_texture_measure_type((int)measure)); } /// - /// Destroy a texture and free the texture. + /// Destroys a texture and removes its reference in the textures list. /// - /// The type of texture - /// The options + /// Type of texture as an int (0 for Image, 1 for Measure). + /// Corresponding options enum (sl.VIEW if Image type, sl.MEASURE if Measure type) as an integer. private void DestroyTexture(int type, int option) { if (textures.ContainsKey(type) && textures[type].ContainsKey(option)) @@ -1298,7 +1461,7 @@ private void DestroyTexture(int type, int option) } /// - /// Destroy all textures + /// Destroy all textures that were ever requested. /// private void DestroyAllTexture() { @@ -1314,29 +1477,29 @@ private void DestroyAllTexture() /// - /// Destroy a texture created with CreateTextureImageType + /// Destroy a texture created with CreateTextureImageType(). /// - /// The option of the texture + /// View type (left RGB, right depth image, etc.) as an integer. private void DestroyTextureImageType(int option) { DestroyTexture((int)TYPE_VIEW.RETRIEVE_IMAGE, option); } /// - /// Destroy a texture created with CreateTextureMeasureType + /// Destroy a texture created with CreateTextureMeasureType(). /// - /// The option of the texture + /// Measure type (depth, confidence, etc.) as an integer. private void DestroyTextureMeasureType(int option) { DestroyTexture((int)TYPE_VIEW.RETRIEVE_MEASURE, option); } /// - /// Retrieves a texture previously created + /// Retrieves a texture that was already created. /// - /// The type of texture - /// The mode - /// The texture + /// Type of texture as an integer (0 for Image, 1 for Measure). + /// Corresponding options enum (sl.VIEW if Image type, sl.MEASURE if Measure type) as an integer. + /// Existing texture of the given type/mode. public Texture2D GetTexture(TYPE_VIEW type, int mode) { if (HasTexture((int)type, mode)) @@ -1347,56 +1510,27 @@ public Texture2D GetTexture(TYPE_VIEW type, int mode) } /// - /// Check if a texture is available + /// Checks if a texture of a given type has already been created. /// - /// The type of texture - /// The mode - /// True if the texture is available + /// Type of texture as an integer (0 for Image, 1 for Measure). + /// Corresponding options enum (sl.VIEW if Image type, sl.MEASURE if Measure type) as an integer. + /// True if the texture is available. private bool HasTexture(int type, int mode) { - if (cameraReady) + if (cameraReady) //Texture can't exist if the ZED hasn't been initialized yet. { return textures.ContainsKey((int)type) && textures[type].ContainsKey((int)mode); } return false; } - /// - /// Width of the images returned by the ZED - /// - public int ImageWidth - { - get - { - return imageWidth; - } - } - - /// - /// Returns the height of the image - /// - public int ImageHeight - { - get - { - return imageHeight; - } - } - /// - /// The projection which corresponds to the traits of the ZED - /// - public Matrix4x4 Projection - { - get - { - return projection; - } - } /// - /// Sets a filtering value for the disparity map (and by extension the depth map). The function should be called before the grab to be taken into account. + /// Sets a filtering value for the disparity map (and by extension the depth map). The filter removes depth values if their confidence + /// value is below the filtering value. Should be called before any Grab() that should take the threshold into account. /// - /// a value in [1,100]. A lower value means more confidence and precision (but less density), an upper value reduces the filtering (more density, less certainty). Other value means no filtering. + /// Value in [1,100]. Lower values mean more confidence and precision, but less density. + /// Upper values result in more density, but less confidence overall. Values outside the range result in no filtering. /// public void SetConfidenceThreshold(int threshold) { @@ -1404,16 +1538,17 @@ public void SetConfidenceThreshold(int threshold) } /// - /// Set the maximum distance of depth/disparity estimation (all values after this limit will be reported as TOO_FAR value) + /// Sets the maximum distance of depth/disparity estimation. All values beyond will be reported as TOO_FAR and not used. /// - /// maximum distance in the defined UNIT + /// Maximum distance in the units set in the InitParameters used in Init(). public void SetDepthMaxRangeValue(float distanceMax) { dllz_set_depth_max_range_value(distanceMax); } /// - /// Returns the current fps + /// Returns the current camera FPS. This is limited primarily by resolution but can also be lower due to + /// setting a lower desired resolution in Init() or from USB connection/bandwidth issues. /// /// The current fps public float GetCameraFPS() @@ -1421,10 +1556,7 @@ public float GetCameraFPS() return dllz_get_camera_fps(); } - public float GetRequestedCameraFPS() - { - return fpsMax; - } + public CalibrationParameters GetCalibrationParameters(bool raw=false) { @@ -1445,141 +1577,142 @@ public CalibrationParameters GetCalibrationParameters(bool raw=false) return parameters; - } /// - /// Gets the zed camera model + /// Gets the ZED camera model (ZED or ZED Mini). /// - /// The camera model (sl.MODEL) + /// Model of the ZED as sl.MODEL. public sl.MODEL GetCameraModel() { return (sl.MODEL)dllz_get_camera_model (); } /// - /// Gets the zed firmware + /// Gets the ZED's firmware version. /// - /// The firmware + /// Firmware version. public int GetZEDFirmwareVersion() { return dllz_get_zed_firmware(); } /// - /// Gets the zed firmware + /// Gets the ZED's serial number. /// - /// The serial number + /// Serial number public int GetZEDSerialNumber() { return dllz_get_zed_serial(); } - /// - /// Returns the vertical field of view in radians + /// Returns the ZED's vertical field of view in radians. /// - /// The field of view + /// Vertical field of view. public float GetFOV() { return GetCalibrationParameters(false).leftCam.vFOV * Mathf.Deg2Rad; } /// - /// Gets the calibration status + /// Gets the status of the ZED's self-calibration process (not called, running, failed or success). /// - /// The calibration status + /// Self-calibration status. public ZED_SELF_CALIBRATION_STATE GetSelfCalibrationStatus() { return (ZED_SELF_CALIBRATION_STATE)dllz_get_self_calibration_state(); } - /// - /// Compute textures from the ZED, the new textures will not be displayed until an event is sent to the Render Thread. + /// Computes textures from the ZED. The new textures will not be displayed until an event is sent to the render thread. + /// This event is called from UpdateTextures(). /// public void RetrieveTextures() { dllz_retrieve_textures(); } - /// - /// swap textures between acquisition and rendering thread + /// Swaps textures safely between the acquisition and rendering threads. /// public void SwapTextures() { dllz_swap_textures(); } - + /// + /// Timestamp of the images used the last time the ZED wrapper updated textures. + /// + /// public ulong GetImagesTimeStamp() { return dllz_get_updated_textures_timestamp(); } /// - /// Get the number of frame dropped since grab() has been called for the first time - /// Based on camera time stamp and fps comparison. - /// - /// number of frame dropped since first grab() call. + /// Gets the number of frames dropped since Grab() was called for the first time. + /// Based on camera timestamps and an FPS comparison. + /// Similar to the Frame Drop display in the ZED Explorer app. + /// Frames dropped since first Grab() call. public uint GetFrameDroppedCount() { return dllz_get_frame_dropped_count(); } /// - /// Get the percentage of frame dropped since grab() has been called for the first time + /// Gets the percentage of frames dropped since Grab() was called for the first time. /// - /// number (percentage) of frame dropped. + /// Percentage of frames dropped. public float GetFrameDroppedPercent() { return dllz_get_frame_dropped_percent (); } /// - /// Gets the position of the camera and the current state of the Tracker + /// Gets the position of the camera and the current state of the ZED Tracking. /// - /// the quaternion will be filled with the current rotation of the camera depending on the reference - /// the vector will be filled with the current position of the camera depending on the reference - /// The reference type will fill the quaternion and vector with either the diffrences between the last pose(CAMERA) or the cumul of poses (WORLD) - /// A tracking frame state + /// Quaternion filled with the current rotation of the camera depending on its reference frame. + /// Vector filled with the current position of the camera depending on its reference frame. + /// Reference frame for setting the rotation/position. CAMERA gives movement relative to the last pose. + /// WORLD gives cumulative movements since tracking started. + /// State of ZED's Tracking system (off, searching, ok). public TRACKING_STATE GetPosition(ref Quaternion rotation, ref Vector3 position, REFERENCE_FRAME referenceType = REFERENCE_FRAME.WORLD) { return (TRACKING_STATE)dllz_get_position(ref rotation, ref position, (int)referenceType); } /// - /// Get the current position of the camera with an optionnal transformation of the camera frame/motion tracking frame. - /// + /// Gets the current position of the camera and state of the tracking, with an optional offset to the tracking frame. /// - /// the quaternion will be filled with the current rotation of the camera depending on the reference - /// the vector will be filled with the current position of the camera depending on the reference - /// - /// - /// - /// - public TRACKING_STATE GetPosition(ref Quaternion rotation, ref Vector3 translation, ref Quaternion targetQuaternion, ref Vector3 targetTranslation, REFERENCE_FRAME mat_type = REFERENCE_FRAME.WORLD) + /// Quaternion filled with the current rotation of the camera depending on its reference frame. + /// Vector filled with the current position of the camera depending on its reference frame. + /// Rotational offset applied to the tracking frame. + /// Positional offset applied to the tracking frame. + /// Reference frame for setting the rotation/position. CAMERA gives movement relative to the last pose. + /// WORLD gives cumulative movements since tracking started. + /// State of ZED's Tracking system (off, searching, ok). + public TRACKING_STATE GetPosition(ref Quaternion rotation, ref Vector3 translation, ref Quaternion targetQuaternion, ref Vector3 targetTranslation, REFERENCE_FRAME referenceFrame = REFERENCE_FRAME.WORLD) { - return (TRACKING_STATE)dllz_get_position_at_target_frame(ref rotation, ref translation, ref targetQuaternion, ref targetTranslation, (int)mat_type); + return (TRACKING_STATE)dllz_get_position_at_target_frame(ref rotation, ref translation, ref targetQuaternion, ref targetTranslation, (int)referenceFrame); } - /// - /// Get the current position of the camera with an defined tracking frame (see TRACKING_FRAME ) - /// - /// - /// the quaternion will be filled with the current rotation of the camera depending on the reference and tracking frame - /// the vector will be filled with the current position of the camera depending on the reference and trancking frameframe - /// - /// - /// - /// - public TRACKING_STATE GetPosition(ref Quaternion rotation, ref Vector3 translation, TRACKING_FRAME tracking_frame, REFERENCE_FRAME mat_type = REFERENCE_FRAME.WORLD) + /// + /// Gets the current position of the camera and state of the tracking, with a defined tracking frame. + /// A tracking frame defines what part of the ZED is its center for tracking purposes. See ZEDCommon.TRACKING_FRAME. + /// + /// Quaternion filled with the current rotation of the camera depending on its reference frame. + /// Vector filled with the current position of the camera depending on its reference frame. + /// Center of the ZED for tracking purposes (left eye, center, right eye). + /// Reference frame for setting the rotation/position. CAMERA gives movement relative to the last pose. + /// WORLD gives cumulative movements since tracking started. + /// State of ZED's Tracking system (off, searching, ok). + public TRACKING_STATE GetPosition(ref Quaternion rotation, ref Vector3 translation, TRACKING_FRAME trackingFrame, REFERENCE_FRAME referenceFrame = REFERENCE_FRAME.WORLD) { Quaternion rotationOffset = Quaternion.identity; Vector3 positionOffset = Vector3.zero; - switch (tracking_frame) + switch (trackingFrame) //Add offsets to account for different tracking frames. { case sl.TRACKING_FRAME.LEFT_EYE: positionOffset = new Vector3(0, 0, 0); @@ -1592,15 +1725,16 @@ public TRACKING_STATE GetPosition(ref Quaternion rotation, ref Vector3 translati break; } - return (TRACKING_STATE)dllz_get_position_at_target_frame(ref rotation, ref translation, ref rotationOffset, ref positionOffset, (int)mat_type); + return (TRACKING_STATE)dllz_get_position_at_target_frame(ref rotation, ref translation, ref rotationOffset, ref positionOffset, (int)referenceFrame); } - /// - /// Get position and fill a pose + /// + /// Gets the current position of the camera and state of the tracking, filling a Pose struct useful for AR pass-through. /// - /// current pose - /// reference frame for the tracking - /// + /// Current pose. + /// Reference frame for setting the rotation/position. CAMERA gives movement relative to the last pose. + /// WORLD gives cumulative movements since tracking started. + /// State of ZED's Tracking system (off, searching, ok). public TRACKING_STATE GetPosition(ref Pose pose, REFERENCE_FRAME referenceType = REFERENCE_FRAME.WORLD) { return (TRACKING_STATE)dllz_get_position_data(ref pose, (int)referenceType); @@ -1608,10 +1742,12 @@ public TRACKING_STATE GetPosition(ref Pose pose, REFERENCE_FRAME referenceType = /// - /// Set a prior to the IMU orientation (only for ZED-M). Prior must come from a external IMU such as the Hmd orientation and must be as much as possible in the same timeframe than the camera + /// Sets a prior to the IMU orientation (only for ZED-M). + /// Prior must come from a external IMU, such as the HMD orientation and should be in a time frame + /// that's as close as possible to the camera. /// - /// Error code status - /// Rotation. + /// Error code status. + /// Prior rotation. public ERROR_CODE SetIMUOrientationPrior(ref Quaternion rotation) { sl.ERROR_CODE trackingStatus = sl.ERROR_CODE.CAMERA_NOT_DETECTED; @@ -1619,12 +1755,11 @@ public ERROR_CODE SetIMUOrientationPrior(ref Quaternion rotation) return trackingStatus; } - /// - /// Get the quaternion given by the IMU of the ZED-M (only available for ZED-M) + /// Gets the rotation given by the ZED Mini's IMU. Doesn't work if using the original ZED. /// - /// Error code status - /// Rotation. + /// Error code status. + /// Rotation from the IMU. public ERROR_CODE GetInternalIMUOrientation(ref Quaternion rotation, TIME_REFERENCE referenceTime = TIME_REFERENCE.IMAGE) { sl.ERROR_CODE err = sl.ERROR_CODE.CAMERA_NOT_DETECTED; @@ -1633,10 +1768,10 @@ public ERROR_CODE GetInternalIMUOrientation(ref Quaternion rotation, TIME_REFERE } /// - /// Get the full imu data (raw value and fused values) given by the IMU of the ZED-M (only available for ZED-M) + /// Gets the full IMU data (raw value and fused values) from the ZED Mini. Doesn't work if using the original ZED. /// - /// Error code status - /// Rotation. + /// Error code status. + /// Rotation from the IMU. public ERROR_CODE GetInternalIMUData(ref IMUData data, TIME_REFERENCE referenceTime = TIME_REFERENCE.IMAGE) { sl.ERROR_CODE err = sl.ERROR_CODE.CAMERA_NOT_DETECTED; @@ -1645,10 +1780,10 @@ public ERROR_CODE GetInternalIMUData(ref IMUData data, TIME_REFERENCE referenceT } /// - /// Converts a float array to a matrix + /// Converts a float array to a matrix. /// - /// - /// + /// Matrix to be filled. + /// Float array to be turned into a matrix. static public void Float2Matrix(ref Matrix4x4 m, float[] f) { if (f == null) return; @@ -1663,20 +1798,20 @@ static public void Float2Matrix(ref Matrix4x4 m, float[] f) } /// - /// Set settings of the camera + /// Sets a value in the ZED's camera settings. /// - /// The setting which will be changed - /// The value - /// will set default (or automatic) value if set to true (value (int) will not be taken into account) + /// Setting to be changed (brightness, contrast, gain, exposure, etc.) + /// New value. + /// If true, ignores the value and applies the default setting. public void SetCameraSettings(CAMERA_SETTINGS settings, int value, bool usedefault = false) { cameraSettingsManager.SetCameraSettings(settings, value, usedefault); } /// - /// Get the value from a setting of the camera + /// Gets the value of a given setting from the ZED camera. /// - /// + /// Setting to be retrieved (brightness, contrast, gain, exposure, etc.) public int GetCameraSettings(CAMERA_SETTINGS settings) { AssertCameraIsReady(); @@ -1684,25 +1819,28 @@ public int GetCameraSettings(CAMERA_SETTINGS settings) } /// - /// Load the camera settings (brightness, contrast, hue, saturation, gain, exposure) + /// Loads camera settings (brightness, contrast, hue, saturation, gain, exposure) from a file in the + /// project's root directory. /// - /// + /// Filename. public void LoadCameraSettings(string path) { cameraSettingsManager.LoadCameraSettings(instance, path); } /// - /// Save the camera settings (brightness, contrast, hue, saturation, gain, exposure) + /// Save the camera settings (brightness, contrast, hue, saturation, gain, exposure) to a file + /// relative to the project's root directory. /// - /// + /// Filename. public void SaveCameraSettings(string path) { cameraSettingsManager.SaveCameraSettings(path); } /// - /// Retrirves camera settings from the camera + /// Retrieves camera settings from the ZED camera and loads them into a CameraSettings instance + /// handled by ZEDCameraSettingsManager. /// public void RetrieveCameraSettings() { @@ -1710,7 +1848,8 @@ public void RetrieveCameraSettings() } /// - /// Returns a copy of the camera settings, cannot be modified + /// Returns a copy of the camera settings from ZEDCameraSettingsManager. Modifying this copy + /// has no effect on the camera or ZEDCameraSettingsManager. /// /// public ZEDCameraSettingsManager.CameraSettings GetCameraSettings() @@ -1719,25 +1858,25 @@ public ZEDCameraSettingsManager.CameraSettings GetCameraSettings() } /// - /// Return the state of the exposure (true = automatic, false = manual) + /// Returns if the camera's exposure mode is set to automatic. /// - /// + /// True if automatic, false if manual. public bool GetExposureUpdateType() { return cameraSettingsManager.auto; } /// - /// Return the state of the white balance (true = automatic, false = manual) + /// Returns if the camera's white balance is set to automatic. /// - /// + /// True if automatic, false if manual. public bool GetWhiteBalanceUpdateType() { return cameraSettingsManager.whiteBalanceAuto; } /// - /// Set all the settings registered, to the camera + /// Applies all the settings registered in the ZEDCameraSettingsManager instance to the actual ZED camera. /// public void SetCameraSettings() { @@ -1745,56 +1884,57 @@ public void SetCameraSettings() } /// - /// The function checks if ZED cameras are connected, can be called before instantiating a Camera object + /// Checks if the ZED camera is connected. /// - /// On Windows, only one ZED is accessible so this function will return 1 even if multiple ZED are connected. - /// the number of connected ZED + /// The C++ SDK version of this call returns the number of connected ZEDs. But multiple ZEDs aren't supported in the Unity plugin. + /// True if ZED is connected. public static bool IsZedConnected() { return Convert.ToBoolean(dllz_is_zed_connected()); } /// - /// The function return the version of the currently installed ZED SDK + /// Gets the version of the currently installed ZED SDK. /// - /// ZED SDK version as a string with the following format : MAJOR.MINOR.PATCH + /// ZED SDK version as a string in the format MAJOR.MINOR.PATCH. public static string GetSDKVersion() { return PtrToStringUtf8(dllz_get_sdk_version()); } /// - /// Check if camera has been initialized, or if the plugin has been loaded + /// Checks if the camera has been initialized and the plugin has been loaded. Throws exceptions otherwise. /// private void AssertCameraIsReady() { if (!cameraReady) - throw new Exception("Camera is not connected or init was not called"); + throw new Exception("ZED camera is not connected or Init() was not called."); if (!pluginIsReady) - throw new Exception("Could not resolve plugin dependencies"); + throw new Exception("Could not resolve ZED plugin dependencies."); } /// - /// retrieve the images from the ZED and send an event to update the textures + /// Deploys an event that causes the textures to be updated with images received from the ZED. + /// Should be called after RetrieveTextures() so there are new images available. /// public void UpdateTextures() { - //Retrieves the images from the ZED - //RetrieveTextures(); - GL.IssuePluginEvent(GetRenderEventFunc(), 1); + GL.IssuePluginEvent(GetRenderEventFunc(), 1); } - ///////////////////////////////////////////// SINGLE PIXEL UTILS FUNCTIONS //////////////////////////////////////////////// + ///////////////////////////// SINGLE PIXEL UTILITY FUNCTIONS //////////////////////////////// /// - /// Get the current depth value in the UNIT - /// The pixel as a vector3 where the component Z is unused, this position has to be in the screen dimensions "GetDepthValue(Input.mousePosition)" works only if the zed image fills the whole screen - /// the depth value as a float - /// - public float GetDepthValue(Vector3 pixel) + /// Gets the current depth value of a pixel in the UNITS specified when the camera was started with Init(). + /// May result in errors if the ZED image does not fill the whole screen. + /// The pixel's screen space coordinates as a Vector3. + /// The Z component is unused - designed to take input from Input.mousePosition. + /// Depth value as a float. + /// + public float GetDepthValue(Vector3 pixel) { if (!cameraReady) { @@ -1810,15 +1950,17 @@ public float GetDepthValue(Vector3 pixel) return d; } - /// - /// Get the current euclidean distance( sqrt(x²+y²+z²)) value of the targeted pixelof the screen to the camera. - /// The pixel as a vector3 where the component Z is unused, this position has to be in the screen dimensions "GetDistancehValue(Input.mousePosition)" works only if the zed image fills the whole screen - /// the distance in float - /// - public float GetDistanceValue(Vector3 pixel) + /// + /// Gets the current Euclidean distance (sqrt(x²+y²+z²)) of the targeted pixel of the screen to the camera. + /// May result in errors if the ZED image does not fill the whole screen. + /// The pixel's screen space coordinates as a Vector3. + /// The Z component is unused - designed to take input from Input.mousePosition. + /// Distance as a float. + /// + public float GetDistanceValue(Vector3 pixel) { - if (!cameraReady) - { + if (!cameraReady) //Do nothing if the ZED isn't initialized. + { return -1; } float posX = ImageWidth * (float)pixel.x / (float)Screen.width; @@ -1829,15 +1971,16 @@ public float GetDistanceValue(Vector3 pixel) return dllz_get_distance_value((uint)posX, (uint)posY); } - /// - /// Get the (x,y,z) position of the pixel, relative to the camera frame - /// The pixel as a vector3 where the component Z is unused, this position has to be in the screen dimensions "GetNormalValue(Input.mousePosition)" works only if the zed image fills the whole screen - /// true if success. xyz will be then filled with the appropriate values - /// - public bool GETXYZValue(Vector3 pixel, out Vector4 xyz) + /// + /// Gets the position of a camera-space pixel relative to the camera frame. + /// The pixel's screen space coordinates as a Vector3. + /// The Z component is unused - designed to take input from Input.mousePosition. + /// Position relative to the camera. + /// True if successful. + /// + public bool GetXYZValue(Vector3 pixel, out Vector4 xyz) { - - if (!cameraReady) + if (!cameraReady) //Do nothing if the ZED isn't initialized. { xyz = Vector3.zero; return false; @@ -1853,15 +1996,17 @@ public bool GETXYZValue(Vector3 pixel, out Vector4 xyz) /// - /// Get the current normal value in the UNIT - /// The normal is in the camera frame. Use cam.worldToCameraMatrix.inverse to transform to world normals. Or use the ZEDSupportFunctions - /// The pixel as a vector3, the component Z is unused, this position has to be in the screen dimensions "GetNormalValue(Input.mousePosition)" works only if the zed image fills the whole screen - /// true if success. normal will be then filled with the appropriate values + /// Gets the normal of a camera-space pixel. The normal is relative to the camera. + /// Use cam.worldToCameraMatrix.inverse to transform it to world space. + /// Note that ZEDSupportFunctions contains high-level versions of this function that are easier to use. + /// The pixel's screen space coordinates as a Vector3. + /// The Z component is unused - designed to take input from Input.mousePosition. + /// Normal value of the pixel as a Vector4. + /// True if successful. /// public bool GetNormalValue(Vector3 pixel, out Vector4 normal) { - - if (!cameraReady) + if (!cameraReady) //Do nothing if the ZED isn't initialized. { normal = Vector3.zero; return false; @@ -1875,19 +2020,14 @@ public bool GetNormalValue(Vector3 pixel, out Vector4 normal) bool r = dllz_get_normal_value((uint)posX, (uint)posY, out normal) != 0; return r; - - } - - - /// - /// Initializes and starts the spatial mapping processes. + /// Initializes and begins the spatial mapping processes. /// - /// Spatial mapping resolution in meters - /// Minimum depth integration range in meters - /// Maximum depth integration range in meters + /// Spatial mapping resolution in meters. + /// Maximum scanning range in meters. + /// True to scan surface textures in addition to geometry. /// public sl.ERROR_CODE EnableSpatialMapping(float resolution_meter, float max_range_meter, bool saveTexture = false) { @@ -1902,7 +2042,6 @@ public sl.ERROR_CODE EnableSpatialMapping(float resolution_meter, float max_rang /// /// Disables the Spatial Mapping process. /// - /// public void DisableSpatialMapping() { lock (ZEDManager.Instance.grabLock) @@ -1912,37 +2051,39 @@ public void DisableSpatialMapping() } /// - /// Update the internal version of the mesh and return the sizes of the meshes. + /// Updates the internal version of the mesh and returns the sizes of the meshes. /// - /// Vector containing the number of vertices in each submeshes. - /// Vector containing the number of triangles in each submeshes. - /// Number of submeshes. - /// List of the submeshes updated since the last update. - /// Total number of updated vertices for all submeshes. - /// Total number of updated triangles for all submeshes. - /// Maximal number of submeshes handle in the script. - /// - public sl.ERROR_CODE UpdateMesh(int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmeshMax) + /// Array of the number of vertices in each submesh. + /// Array of the number of triangles in each submesh. + /// Number of submeshes. + /// List of all submeshes updated since the last update. + /// Total number of updated vertices in all submeshes. + /// Total number of updated triangles in all submeshes. + /// Maximum number of submeshes that can be handled. + /// Error code indicating if the update was successful, and why it wasn't otherwise. + public sl.ERROR_CODE UpdateMesh(int[] nbVerticesInSubmeshes, int[] nbTrianglesInSubmeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmeshMax) { sl.ERROR_CODE err = sl.ERROR_CODE.FAILURE; - err = (sl.ERROR_CODE)dllz_update_mesh(nbVerticesInSubemeshes, nbTrianglesInSubemeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmeshMax); + err = (sl.ERROR_CODE)dllz_update_mesh(nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmeshMax); return err; } /// - /// Retrieves all the chunks of the generated mesh. You need to call UpdateMesh first. vertices and triangles must be at least of the size returned by UpdateMesh (nbVertices and nbTriangles). + /// Retrieves all chunks of the generated mesh. Call UpdateMesh() before calling this. + /// Vertex and triangle arrays must be at least of the sizes returned by UpdateMesh (nbVertices and nbTriangles). /// - /// Vertices are defined by a 3D point - /// Triangles (or faces) contains the index of its three vertices - /// Maximal number of submeshes handle in the script. - /// + /// Vertices of the mesh. + /// Triangles, formatted as the index of each triangle's three vertices in the vertices array. + /// Maximum number of submeshes that can be handled. + /// Error code indicating if the retrieval was successful, and why it wasn't otherwise. public sl.ERROR_CODE RetrieveMesh(Vector3[] vertices, int[] triangles, int nbSubmeshMax, Vector2[] uvs, IntPtr textures) { return (sl.ERROR_CODE)dllz_retrieve_mesh(vertices, triangles, nbSubmeshMax, uvs, textures); } /// - /// Starts the mesh generation process in a non blocking thread from the spatial mapping process. + /// Starts the mesh generation process in a thread that doesn't block the spatial mapping process. + /// ZEDSpatialMappingHelper calls this each time it has finished applying the last mesh update. /// public void RequestMesh() { @@ -1950,87 +2091,87 @@ public void RequestMesh() } /// - /// Switches the pause status of the data integration mechanism for the spatial mapping. + /// Sets the pause state of the data integration mechanism for the ZED's spatial mapping. /// - /// if true, the integration is paused. If false, the spatial mapping is resumed. + /// If true, the integration is paused. If false, the spatial mapping is resumed. public void PauseSpatialMapping(bool status) { dllz_pause_spatial_mapping(status); } /// - /// Returns the mesh generation status, useful to after calling requestMeshAsync. + /// Returns the mesh generation status. Useful for knowing when to update and retrieve the mesh. /// - /// If true, the integration is paused. If false, the spatial mapping is resumed. public sl.ERROR_CODE GetMeshRequestStatus() { return (sl.ERROR_CODE)dllz_get_mesh_request_status_async(); } /// - /// Save the mesh in a specific file format + /// Saves the scanned mesh in a specific file format. /// - /// the path and filename of the mesh. - /// defines the file format (extension). - /// + /// Path and filename of the mesh. + /// File format (extension). Can be .obj, .ply or .bin. public bool SaveMesh(string filename, MESH_FILE_FORMAT format) { return dllz_save_mesh(filename, format); } /// - /// Loads a mesh + /// Loads a saved mesh file. ZEDSpatialMapping then configures itself as if the loaded mesh was just scanned. /// - /// The path and filename of the mesh (do not forget the extension). - /// Vector containing the number of vertices in each submeshes. - /// Vector containing the number of triangles in each submeshes. - /// Number of submeshes. - /// List of the submeshes updated since the last update. - /// Total number of updated vertices for all submeshes. - /// Total number of updated triangles for all submeshes. - /// Maximal number of submeshes handle in the script. - /// Vector containing the size of all the texture (width, height). - /// - public bool LoadMesh(string filename, int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmeshMax, int[] textureSize = null) + /// Path and filename of the mesh. Should include the extension (.obj, .ply or .bin). + /// Array of the number of vertices in each submesh. + /// Array of the number of triangles in each submesh. + /// Number of submeshes. + /// List of all submeshes updated since the last update. + /// Total number of updated vertices in all submeshes. + /// Total number of updated triangles in all submeshes. + /// Maximum number of submeshes that can be handled. + /// Array containing the sizes of all the textures (width, height) if applicable. + public bool LoadMesh(string filename, int[] nbVerticesInSubmeshes, int[] nbTrianglesInSubmeshes, ref int nbSubmeshes, int[] updatedIndices, + ref int nbVertices, ref int nbTriangles, int nbSubmeshMax, int[] textureSize = null) { - return dllz_load_mesh(filename, nbVerticesInSubemeshes, nbTrianglesInSubemeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmeshMax, textureSize); + return dllz_load_mesh(filename, nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, + ref nbTriangles, nbSubmeshMax, textureSize); } /// - /// Filters a mesh; less triangles + /// Filters a mesh to remove triangles while still preserving its overall shape (though less accurate). /// - /// Parameters for the optional filtering step of a mesh - /// Vector containing the number of vertices in each submeshes after filtering. - /// Vector containing the number of triangles in each submeshes after filtering. - /// Number of submeshes after filtering. - /// List of the submeshes updated by the filter. - /// Total number of updated vertices for all submeshes after filtering. - /// Total number of updated triangles for all submeshes after filtering. - /// Maximal number of submeshes handle in the script. - /// + /// Filter level. Higher settings remove more triangles. + /// Array of the number of vertices in each submesh. + /// Array of the number of triangles in each submesh. + /// Number of submeshes. + /// List of all submeshes updated since the last update. + /// Total number of updated vertices in all submeshes. + /// Total number of updated triangles in all submeshes. + /// Maximum number of submeshes that can be handled. public bool FilterMesh(FILTER filterParameters, int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmeshMax) { return dllz_filter_mesh(filterParameters, nbVerticesInSubemeshes, nbTrianglesInSubemeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmeshMax); } - /// Apply the texture on the internal mesh, you will need to call RetrieveMesh with uvs and textures to get the mesh + /// + /// Applies the scanned texture onto the internal scanned mesh. + /// You will need to call RetrieveMesh() with uvs and textures to get the result into Unity. /// - /// Vector containing the number of vertices in each textured submeshes. - /// Vector containing the number of triangles in each textured submeshes after filtering. - /// Number of submeshes after filtering. - /// List of the submeshes updated by the texture mapping. - /// Total number of updated vertices for all submeshes. - /// Total number of updated triangles for all submeshes. + /// Array of the number of vertices in each submesh. + /// Array of the number of triangles in each submesh. + /// Number of submeshes. + /// List of all submeshes updated since the last update. + /// Total number of updated vertices in all submeshes. + /// Total number of updated triangles in all submeshes. /// Vector containing the size of all the texture (width, height). - /// Maximal number of submeshes handle in the script. + /// Maximum number of submeshes that can be handled. /// - public bool ApplyTexture(int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int[] textureSize, int nbSubmeshMax) + public bool ApplyTexture(int[] nbVerticesInSubmeshes, int[] nbTrianglesInSubmeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int[] textureSize, int nbSubmeshMax) { - return dllz_apply_texture(nbVerticesInSubemeshes, nbTrianglesInSubemeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, textureSize, nbSubmeshMax); + return dllz_apply_texture(nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, textureSize, nbSubmeshMax); } /// - /// Get the current state of spatial mapping + /// Gets the current state of spatial mapping. /// /// public SPATIAL_MAPPING_STATE GetSpatialMappingState() @@ -2038,6 +2179,12 @@ public SPATIAL_MAPPING_STATE GetSpatialMappingState() return (sl.SPATIAL_MAPPING_STATE)dllz_get_spatial_mapping_state(); } + /// + /// Gets a vector pointing toward the direction of gravity. This is estimated from a 3D scan of the environment, + /// and as such, a scan must be started/finished for this value to be calculated. + /// If using the ZED Mini, this isn't required thanks to its IMU. + /// + /// Vector3 pointing downward. public Vector3 GetGravityEstimate() { Vector3 v = Vector3.zero; @@ -2046,56 +2193,73 @@ public Vector3 GetGravityEstimate() } /// - /// Reshape the chunks, to get more mesh per chunks and less chunks + /// Consolidates the chunks from a scan. This is used to turn lots of small meshes (which are efficient for + /// the scanning process) into several large meshes (which are more convenient to work with). /// /// - /// - /// - /// - /// - /// - /// - /// - public void MergeChunks(int numberFaces, int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmesh) - { - dllz_spatial_mapping_merge_chunks(numberFaces, nbVerticesInSubemeshes, nbTrianglesInSubemeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmesh); - } - - /// - /// Retrieves images for a specific mat - /// - /// - /// - /// - /// - /// + /// Array of the number of vertices in each submesh. + /// Array of the number of triangles in each submesh. + /// Number of submeshes. + /// List of all submeshes updated since the last update. + /// Total number of updated vertices in all submeshes. + /// Total number of updated triangles in all submeshes. + public void MergeChunks(int numberFaces, int[] nbVerticesInSubmeshes, int[] nbTrianglesInSubmeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmesh) + { + dllz_spatial_mapping_merge_chunks(numberFaces, nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmesh); + } + + /// + /// Retrieves a measure texture from the ZED SDK and loads it into a ZEDMat. Use this to get an individual + /// texture from the last grabbed frame with measurements in every pixel - such as a depth map, confidence map, etc. + /// Measure textures are not human-viewable but don't lose accuracy, unlike image textures. + /// + /// If you want to access the texture via script, you'll usually want to specify CPU memory. Then you can use + /// Marshal.Copy to move them into a new byte array, which you can load into a Texture2D. + /// RetrieveMeasure() calls Camera::retrieveMeasure() in the C++ SDK. For more info, read: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/classsl_1_1Camera.html#af799d12342a7b884242fffdef5588a7f + /// + /// ZEDMat to fill with the new texture. + /// Measure type (depth, confidence, xyz, etc.) + /// Whether the image should be on CPU or GPU memory. + /// Resolution of the texture. + /// Error code indicating if the retrieval was successful, and why it wasn't otherwise. public sl.ERROR_CODE RetrieveMeasure(sl.ZEDMat mat, sl.MEASURE measure, sl.ZEDMat.MEM mem = sl.ZEDMat.MEM.MEM_CPU, sl.Resolution resolution = new sl.Resolution()) { return (sl.ERROR_CODE)(dllz_retrieve_measure(mat.MatPtr, (int)measure, (int)mem, resolution)); } /// - /// Retrieves measures for a specific mat - /// - /// - /// - /// - /// - /// + /// Retrieves an image texture from the ZED SDK and loads it into a ZEDMat. Use this to get an individual + /// texture from the last grabbed frame in a human-viewable format. Image textures work for when you want the result to be visible, + /// such as the direct RGB image from the camera, or a greyscale image of the depth. However it will lose accuracy if used + /// to show measurements like depth or confidence, unlike measure textures. + /// + /// If you want to access the texture via script, you'll usually want to specify CPU memory. Then you can use + /// Marshal.Copy to move them into a new byte array, which you can load into a Texture2D. Note that you may need to + /// change the color space and/or flip the image. + /// RetrieveMeasure() calls Camera::retrieveMeasure() in the C++ SDK. For more info, read: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/classsl_1_1Camera.html#ac40f337ccc76cacd3412b93f7f4638e2 + /// + /// ZEDMat to fill with the new texture. + /// Image type (left RGB, right depth map, etc.) + /// Whether the image should be on CPU or GPU memory. + /// Resolution of the texture. + /// Error code indicating if the retrieval was successful, and why it wasn't otherwise. public sl.ERROR_CODE RetrieveImage(sl.ZEDMat mat, sl.VIEW view, sl.ZEDMat.MEM mem = sl.ZEDMat.MEM.MEM_CPU, sl.Resolution resolution = new sl.Resolution()) { return (sl.ERROR_CODE)(dllz_retrieve_image(mat.MatPtr, (int)view, (int)mem, resolution)); } /// - /// Compute offset optical center + /// Computes offsets of the optical centers used to line up the ZED's images properly with Unity cameras. + /// Called in ZEDRenderingPlane after the ZED finished initializing. /// - /// + /// Distance from a camera in the ZED rig to the quad/Canvas object holding the ZED image. /// public Vector4 ComputeOpticalCenterOffsets(float planeDistance) { IntPtr p = IntPtr.Zero; - sl.CalibrationParameters calib = GetCalibrationParameters (false);//GetCalibrationinstance.CalibrationParametersRectified; + sl.CalibrationParameters calib = GetCalibrationParameters(false); sl.Resolution imageResolution = new sl.Resolution((uint)instance.ImageWidth, (uint)instance.ImageHeight); @@ -2113,12 +2277,21 @@ public Vector4 ComputeOpticalCenterOffsets(float planeDistance) } + /// + /// Plane Detection + /// + - ////* - /// Plane Detection - /// - /// - public sl.ERROR_CODE findFloorPlane(ref ZEDPlaneGameObject.PlaneData plane,out float playerHeight, Quaternion priorQuat, Vector3 priorTrans) + /// + /// Looks for a plane in the visible area that is likely to represent the floor. + /// Use ZEDPlaneDetectionManager.DetectFloorPlane for a higher-level version that turns planes into GameObjects. + /// + /// Data on the detected plane. + /// Height of the camera from the newly-detected floor. + /// Prior rotation. + /// Prior position. + /// + public sl.ERROR_CODE findFloorPlane(ref ZEDPlaneGameObject.PlaneData plane, out float playerHeight, Quaternion priorQuat, Vector3 priorTrans) { IntPtr p = IntPtr.Zero; Quaternion out_quat = Quaternion.identity; @@ -2134,13 +2307,28 @@ public sl.ERROR_CODE findFloorPlane(ref ZEDPlaneGameObject.PlaneData plane,out f } else return sl.ERROR_CODE.FAILURE; } - - public int convertFloorPlaneToMesh(Vector3[] vertices, int[] triangles,out int numVertices, out int numTriangles) + /// + /// Using data from a detected floor plane, updates supplied vertex and triangle arrays with + /// data needed to make a mesh that represents it. These arrays are updated directly from the wrapper. + /// + /// Array to be filled with mesh vertices. + /// Array to be filled with mesh triangles, stored as indexes of each triangle's points. + /// Total vertices in the mesh. + /// Total triangle indexes (3x number of triangles). + /// + public int convertFloorPlaneToMesh(Vector3[] vertices, int[] triangles, out int numVertices, out int numTriangles) { return dllz_convert_floorplane_to_mesh (vertices, triangles,out numVertices,out numTriangles); } - public sl.ERROR_CODE findPlaneAtHit(ref ZEDPlaneGameObject.PlaneData plane,Vector2 screenPos) + /// + /// Checks for a plane in the real world at given screen-space coordinates. + /// Use ZEDPlaneDetectionManager.DetectPlaneAtHit() for a higher-level version that turns planes into GameObjects. + /// + /// Data on the detected plane. + /// Point on the ZED image to check for a plane. + /// + public sl.ERROR_CODE findPlaneAtHit(ref ZEDPlaneGameObject.PlaneData plane, Vector2 screenPos) { IntPtr p = IntPtr.Zero; Quaternion out_quat = Quaternion.identity; @@ -2161,6 +2349,15 @@ public sl.ERROR_CODE findPlaneAtHit(ref ZEDPlaneGameObject.PlaneData plane,Vecto return sl.ERROR_CODE.FAILURE; } + /// + /// Using data from a detected hit plane, updates supplied vertex and triangle arrays with + /// data needed to make a mesh that represents it. These arrays are updated directly from the wrapper. + /// + /// Array to be filled with mesh vertices. + /// Array to be filled with mesh triangles, stored as indexes of each triangle's points. + /// Total vertices in the mesh. + /// Total triangle indexes (3x number of triangles). + /// public int convertHitPlaneToMesh(Vector3[] vertices, int[] triangles,out int numVertices, out int numTriangles) { return dllz_convert_hitplane_to_mesh (vertices, triangles,out numVertices,out numTriangles); diff --git a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCameraSettingsManager.cs b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCameraSettingsManager.cs index 4ed8a097..782c7672 100644 --- a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCameraSettingsManager.cs +++ b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCameraSettingsManager.cs @@ -3,11 +3,16 @@ using System.Runtime.InteropServices; /// -/// Stores the camera settings and is used as an interface with the ZED -/// -public class ZEDCameraSettingsManager { - - +/// Stores the camera settings (brightness/contrast, gain/exposure, etc.) and interfaces with the ZED +/// when they need to be loaded or changed. +/// Created by ZEDCamera and referenced by ZEDCameraSettingsEditor. +/// +/// The actual settings themselves are stored in an instance of CameraSettings, for easier manipulation. +/// But this class provides accessors for each value within it. +/// +public class ZEDCameraSettingsManager +{ + #region DLL Calls const string nameDll = "sl_unitywrapper"; [DllImport(nameDll, EntryPoint = "dllz_set_camera_settings")] private static extern void dllz_set_camera_settings(int mode, int value, int usedefault); @@ -15,13 +20,29 @@ public class ZEDCameraSettingsManager { [DllImport(nameDll, EntryPoint = "dllz_get_camera_settings")] private static extern int dllz_get_camera_settings(int mode); + #endregion + /// - /// Container of the camera settings + /// Container for ZED camera settings, with constructors for easily creating default or specific values + /// or making duplicate instances. /// public class CameraSettings { + /// + /// Holds an int for each setting, with indexes corresponding to sl.CAMERA_SETTINGS. + /// public int[] settings = new int[System.Enum.GetNames(typeof(sl.CAMERA_SETTINGS)).Length]; + /// + /// Constructor. Call without arguments to set all values to default. + /// + /// Camera's brightness setting. + /// Camera's contrast setting. + /// Camera's hue setting. + /// Camera's saturation setting. + /// Camera's white balance setting. -1 means automatic. + /// Camera's gain setting. -1 means automatic. + /// Camera's exposure setting. -1 means automatic. public CameraSettings(int brightness = 4, int contrast = 4, int hue = 0, int saturation = 4, int whiteBalance = -1, int gain = -1, int exposure = -1) { settings = new int[System.Enum.GetNames(typeof(sl.CAMERA_SETTINGS)).Length]; @@ -34,6 +55,10 @@ public CameraSettings(int brightness = 4, int contrast = 4, int hue = 0, int sat settings[(int)sl.CAMERA_SETTINGS.EXPOSURE] = exposure; } + /// + /// Constructor. Sets settings to match another CameraSettings passed in the argument. + /// + /// public CameraSettings(CameraSettings other) { settings = new int[System.Enum.GetNames(typeof(sl.CAMERA_SETTINGS)).Length]; @@ -46,12 +71,18 @@ public CameraSettings(CameraSettings other) settings[(int)sl.CAMERA_SETTINGS.EXPOSURE] = other.settings[(int)sl.CAMERA_SETTINGS.EXPOSURE]; } + /// + /// Returns a new instance of CameraSettings with the same settings as the instance this function was called with. + /// + /// New instance of CameraSettings. public CameraSettings Clone() { return new CameraSettings(this); } - + /// + /// ZED camera's brightness setting. + /// public int Brightness { get @@ -65,6 +96,9 @@ public int Brightness } } + /// + /// ZED camera's saturation setting. + /// public int Saturation { get @@ -78,6 +112,9 @@ public int Saturation } } + /// + /// ZED camera's hue setting. + /// public int Hue { get @@ -91,6 +128,9 @@ public int Hue } } + /// + /// ZED camera's contrast setting. + /// public int Contrast { get @@ -104,6 +144,9 @@ public int Contrast } } + /// + /// ZED camera's gain setting. -1 means automatic. + /// public int Gain { get @@ -117,6 +160,9 @@ public int Gain } } + /// + /// ZED camera's exposure setting. -1 means automatic. + /// public int Exposure { get @@ -129,6 +175,10 @@ public int Exposure settings[(int)sl.CAMERA_SETTINGS.EXPOSURE] = value; } } + + /// + /// ZED camera's white balance setting. -1 means automatic. + /// public int WhiteBalance { get @@ -144,30 +194,39 @@ public int WhiteBalance } /// - /// Reference to the container + /// Reference to the settings container object. /// private CameraSettings settings_; + /// + /// Reference to the settings container object. + /// public CameraSettings Settings { get { return settings_.Clone(); } } /// - /// Is in auto mode + /// Whether exposure is set to automatic. /// public bool auto = true; - public bool whiteBalanceAuto = true; + /// + /// Whether white balance is set to automatic. + /// + public bool whiteBalanceAuto = true; + /// + /// Constructor. Creates a new instance of CameraSettings to contain all settings values. + /// public ZEDCameraSettingsManager() { settings_ = new CameraSettings(); } /// - /// Set settings from the container to the camera + /// Applies all settings from the container to the actual ZED camera. /// - /// + /// Current instance of the ZEDCamera wrapper. public void SetSettings(sl.ZEDCamera zedCamera) { if (zedCamera != null) @@ -186,7 +245,8 @@ public void SetSettings(sl.ZEDCamera zedCamera) } /// - /// Load camera settings from a file, and set them to the container and camera + /// Loads camera settings from a file, and sets them to the container and camera. + /// File is loaded from the root project folder (one above Assets). /// /// /// @@ -249,7 +309,7 @@ public void LoadCameraSettings(sl.ZEDCamera zedCamera, string path = "ZED_Settin /// - /// Retrieves settings from the camera + /// Retrieves current settings from the ZED camera. /// /// public void RetrieveSettingsCamera(sl.ZEDCamera zedCamera) @@ -267,11 +327,11 @@ public void RetrieveSettingsCamera(sl.ZEDCamera zedCamera) } /// - /// Set settings of the camera + /// Applies an individual setting to the ZED camera. /// - /// The setting which will be changed - /// The value - /// will set default (or automatic) value if set to true (value (int) will not be taken into account) + /// Setting to be changed (brightness, contrast, gain, exposure, etc.) + /// New value for the setting. + /// If true, ignores the value and applies the default setting. public void SetCameraSettings(sl.CAMERA_SETTINGS settings, int value, bool usedefault = false) { settings_.settings[(int)settings] = !usedefault && value != -1 ? value : -1; @@ -279,9 +339,10 @@ public void SetCameraSettings(sl.CAMERA_SETTINGS settings, int value, bool usede } /// - /// Get the value from a setting of the camera + /// Gets the value from an individual ZED camera setting (brightness, contrast, gain, exposure, etc.) /// - /// + /// Setting to be retrieved. + /// Current value. public int GetCameraSettings(sl.CAMERA_SETTINGS settings) { settings_.settings[(int)settings] = dllz_get_camera_settings((int)settings); @@ -289,9 +350,9 @@ public int GetCameraSettings(sl.CAMERA_SETTINGS settings) } /// - /// Save the camera settings into a file + /// Saves all camera settings into a file into the specified path/name. /// - /// + /// Path and filename to save the file (ex. /Assets/ZED_Settings.conf) public void SaveCameraSettings(string path) { using (System.IO.StreamWriter file = new System.IO.StreamWriter(path)) diff --git a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs index 03c14072..bf53bf8b 100644 --- a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs +++ b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs @@ -3,21 +3,35 @@ using System.Runtime.InteropServices; using UnityEngine; +/// +/// This file holds classes built to be exchanged between the ZED wrapper DLL (sl_unitywrapper.dll) +/// and C# scripts within Unity. Most have parity with a structure within the ZED C++ SDK. +/// Find more info at https://www.stereolabs.com/developers/documentation/API/latest/. +/// namespace sl { - + /// + /// Holds a 3x3 matrix that can be marshaled between the ZED + /// Unity wrapper and C# scripts. + /// public struct Matrix3x3 { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] - public float[] m; //3x3 matrix + public float[] m; //3x3 matrix. }; /// - /// Resolution of the current camera + /// Holds a camera resolution as two pointers (for height and width) for easy + /// passing back and forth to the ZED Unity wrapper. /// public struct Resolution { + /// + /// + /// + /// + /// public Resolution(uint width, uint height) { this.width = (System.UIntPtr)width; @@ -30,7 +44,8 @@ public Resolution(uint width, uint height) /// - /// Pose structure + /// Pose structure with data on timing and validity in addition to + /// position and rotation. /// [StructLayout(LayoutKind.Sequential)] public struct Pose @@ -43,64 +58,100 @@ public struct Pose }; /// - /// Full IMU data structure + /// Full IMU data structure. /// [StructLayout(LayoutKind.Sequential)] public struct IMUData { - public Vector3 angularVelocity; //gyroscope raw data in deg/s - public Vector3 linearAcceleration; //accelerometer raw data in m/s² - public Quaternion fusedOrientation; //orientation from gyro/acc fusion - public Matrix3x3 orientationCovariance; //covariance matrix of quaternion - public Matrix3x3 angularVelocityCovariance; //gyroscope raw data covariance matrix - public Matrix3x3 linearAccelerationCovariance; //accelerometer raw data covariance matrix - public int imu_image_sync_val; //rfu + /// + /// Gyroscope raw data in degrees/second. + /// + public Vector3 angularVelocity; + /// + /// Accelerometer raw data in m/s². + /// + public Vector3 linearAcceleration; + /// + /// Orientation from gyro/accelerator fusion. + /// + public Quaternion fusedOrientation; + /// + /// Covariance matrix of the quaternion. + /// + public Matrix3x3 orientationCovariance; + /// + /// Gyroscope raw data covariance matrix. + /// + public Matrix3x3 angularVelocityCovariance; + /// + /// Accelerometer raw data covariance matrix. + /// + public Matrix3x3 linearAccelerationCovariance; + /// + /// RFU. + /// + public int imu_image_sync_val; }; - + /// + /// Calibration information for an individual sensor on the ZED (left or right). + /// For more information, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/structsl_1_1CameraParameters.html [StructLayout(LayoutKind.Sequential)] public struct CameraParameters { /// - /// Focal x + /// Focal X. /// public float fx; /// - /// Focal y + /// Focal Y. /// public float fy; /// - /// Optical center x + /// Optical center X. /// public float cx; /// - /// Optical center y + /// Optical center Y. /// public float cy; + + /// + /// Distortion coefficients. + /// [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U8, SizeConst = 5)] public double[] disto; + /// - /// Vertical field of view after stereo rectification + /// Vertical field of view after stereo rectification. /// public float vFOV; /// - /// Horizontal field of view after stereo rectification + /// Horizontal field of view after stereo rectification. /// public float hFOV; /// - /// Diagonal field of view after stereo rectification + /// Diagonal field of view after stereo rectification. /// public float dFOV; + /// + /// Camera's current resolution. + /// public Resolution resolution; }; - + /// + /// Holds calibration information about the current ZED's hardware, including per-sensor + /// calibration and offsets between the two sensors. + /// For more info, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/structsl_1_1CalibrationParameters.html [StructLayout(LayoutKind.Sequential)] public struct CalibrationParameters { /// - /// Rotation (using Rodrigues' transformation) between the two sensors. Defined as 'tilt', 'convergence' and 'roll' + /// Rotation (using Rodrigues' transformation) between the two sensors. Defined as 'tilt', 'convergence' and 'roll'. /// public Vector3 Rot; /// @@ -108,154 +159,172 @@ public struct CalibrationParameters /// public Vector3 Trans; /// - /// Parameters of the left camera + /// Parameters of the left sensor. /// public CameraParameters leftCam; /// - /// Parameters of the right camera + /// Parameters of the right sensor. /// public CameraParameters rightCam; }; - + /// + /// Container for information about the current SVO recording process. + /// + /// Mirrors sl.RecordingState in the ZED C++ SDK. For more info, visit: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/structsl_1_1RecordingState.html + /// [StructLayout(LayoutKind.Sequential)] public struct Recording_state { /// - /// status of current frame. May be true for success or false if frame could not be written in the SVO file + /// Status of the current frame. True if recording was successful, false if frame could not be written. /// public bool status; /// - /// compression time for the current frame in ms + /// Compression time for the current frame in milliseconds. /// public double current_compression_time; /// - /// compression ratio (% of raw size) for the current frame + /// Compression ratio (% of raw size) for the current frame. /// public double current_compression_ratio; /// - /// average compression time in ms since beginning of recording + /// Average compression time in millisecond since beginning of recording. /// public double average_compression_time; /// - /// compression ratio (% of raw size) since beginning of recording + /// Compression ratio (% of raw size) since recording was started. /// public double average_compression_ratio; } /// - /// Status for self calibration. Since v0.9.3, self-calibration is done in background and start in the sl.ZEDCamera.Init or Reset function. - /// + /// Status of the ZED's self-calibration. Since v0.9.3, self-calibration is done in the background and + /// starts in the sl.ZEDCamera.Init or Reset functions. + /// + /// Mirrors SELF_CALIBRATION_STATE in the ZED C++ SDK. For more info, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/group__Video__group.html#gacce19db438a07075b7e5e22ee5845c95 + /// public enum ZED_SELF_CALIBRATION_STATE { /// - /// Self Calibration has not yet been called (no init called) + /// Self-calibration has not yet been called (no Init() called). /// SELF_CALIBRATION_NOT_CALLED, /// - /// Self Calibration is currently running. + /// Self-calibration is currently running. /// SELF_CALIBRATION_RUNNING, /// - /// Self Calibration has finished running but did not manage to get coherent values. Old Parameters are taken instead. + /// Self-calibration has finished running but did not manage to get coherent values. Old Parameters are used instead. /// SELF_CALIBRATION_FAILED, /// - /// Self Calibration has finished running and did manage to get coherent values. New Parameters are taken. + /// Self Calibration has finished running and successfully produces coherent values. /// SELF_CALIBRATION_SUCCESS }; /// - /// List available depth computation modes. - /// + /// Lists available depth computation modes. Each mode offers better accuracy than the + /// mode before it, but at a performance cost. + /// + /// Mirrors DEPTH_MODE in the ZED C++ SDK. For more info, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/group__Depth__group.html#ga8d542017c9b012a19a15d46be9b7fa43 + /// public enum DEPTH_MODE { /// - /// This mode does not compute any depth map. Only rectified stereo images will be available. + /// Does not compute any depth map. Only rectified stereo images will be available. /// NONE, /// - /// Fastest mode for depth computation. + /// Fastest mode for depth computation. /// PERFORMANCE, /// - /// Balanced quality mode. Depth map is robust in any environment and requires medium resources for computation + /// Balanced quality mode. Depth map is robust in most environment and requires medium compute power. /// MEDIUM, /// - /// Best quality mode. Requires more compute power. + /// Favors accuracy over performance. Requires more compute power. /// QUALITY, /// - /// native depth. Requires more compute power. + /// Native depth. Very accurate, but at a large performance cost. /// - ULTRA, + ULTRA }; - + /// + /// Types of Image view modes, for creating human-viewable textures. + /// Used only in ZEDRenderingPlane as a simplified version of sl.VIEW, which has more detailed options. + /// public enum VIEW_MODE { - /// - /// Eyes will display images (left and right) (default) + /// Dsplays regular color images. /// VIEW_IMAGE, /// - /// Eyes will display depth (left and right) + /// Displays a greyscale depth map. /// VIEW_DEPTH, /// - /// Eyes will display normals (left and right) + /// Displays a normal map. /// VIEW_NORMALS - }; /// - /// List error codes in the ZED SDK. - /// + /// List of error codes in the ZED SDK. + /// + /// Mirrors ERROR_CODE in the ZED C++ SDK. For more info, read: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/group__Camera__group.html#ga4db9ee29f2ff83c71567c12f6bfbf28c + /// public enum ERROR_CODE { /// - /// Operation success + /// Operation was successful. /// - SUCCESS , + SUCCESS, /// - /// Standard code for unsuccessful behavior + /// Standard, generic code for unsuccessful behavior when no other code is more appropriate. /// FAILURE, /// - /// No GPU found or CUDA capability of the device is not supported + /// No GPU found, or CUDA capability of the device is not supported. /// NO_GPU_COMPATIBLE, /// - /// Not enough GPU memory for this depth mode, try a different mode (such as PERFORMANCE). + /// Not enough GPU memory for this depth mode. Try a different mode (such as PERFORMANCE). /// NOT_ENOUGH_GPUMEM, /// - /// The ZED camera is not plugged or detected. + /// The ZED camera is not plugged in or detected. /// CAMERA_NOT_DETECTED, /// - /// a ZED-M camera is detected but the inertial sensor cannot be opened. Only for ZED-M device + /// a ZED Mini is detected but the inertial sensor cannot be opened. (Never called for original ZED) /// SENSOR_NOT_DETECTED, /// - /// For Nvidia Jetson X1 only, resolution not yet supported (USB3.0 bandwidth) + /// For Nvidia Jetson X1 only - resolution not yet supported (USB3.0 bandwidth). /// INVALID_RESOLUTION, /// - /// This issue can occurs when the camera FPS cannot be reached, due to a lot of corrupted frames. Try to change USB port. + /// USB communication issues. Occurs when the camera FPS cannot be reached, due to a lot of corrupted frames. + /// Try changing the USB port. /// LOW_USB_BANDWIDTH, /// - /// ZED calibration file is not found on the host machine. Use ZED Explorer or ZED Calibration to get one + /// ZED calibration file is not found on the host machine. Use ZED Explorer or ZED Calibration to get one. /// CALIBRATION_FILE_NOT_AVAILABLE, /// - /// ZED calibration file is not valid, try to download the factory one or recalibrate your camera using 'ZED Calibration + /// ZED calibration file is not valid. Try downloading the factory one or recalibrating using the ZED Calibration tool. /// INVALID_CALIBRATION_FILE, /// @@ -263,11 +332,11 @@ public enum ERROR_CODE /// INVALID_SVO_FILE, /// - /// An recorder related error occurred (not enough free storage, invalid file) + /// An SVO recorder-related error occurred (such as not enough free storage or an invalid file path). /// SVO_RECORDING_ERROR, /// - /// The requested coordinate system is not available + /// The requested coordinate system is not available. /// INVALID_COORDINATE_SYSTEM, /// @@ -275,19 +344,19 @@ public enum ERROR_CODE /// INVALID_FIRMWARE, /// - /// An invalid parameter has been set for the function + /// An invalid parameter has been set for the function. /// INVALID_FUNCTION_PARAMETERS, /// - /// In grab() only, the current call return the same frame as last call. Not a new frame + /// In grab() only, the current call return the same frame as last call. Not a new frame. /// NOT_A_NEW_FRAME, /// - /// In grab() only, a CUDA error has been detected in the process. Activate verbose in sl::Camera::open for more info + /// In grab() only, a CUDA error has been detected in the process. Activate wrapperVerbose in ZEDManager.cs for more info. /// CUDA_ERROR, /// - /// In grab() only, ZED SDK is not initialized. Probably a missing call to sl::Camera::open + /// In grab() only, ZED SDK is not initialized. Probably a missing call to sl::Camera::open. /// CAMERA_NOT_INITIALIZED, /// @@ -295,7 +364,7 @@ public enum ERROR_CODE /// NVIDIA_DRIVER_OUT_OF_DATE, /// - /// The call of the function is not valid in the current context. Could be a missing call of sl::Camera::open. + /// The function call is not valid in the current context. Could be a missing a call to sl::Camera::open. /// INVALID_FUNCTION_CALL, /// @@ -303,263 +372,308 @@ public enum ERROR_CODE /// CORRUPTED_SDK_INSTALLATION, /// - /// The installed SDK is incompatible SDK used to compile the program + /// The installed SDK is not the SDK used to compile the program. /// INCOMPATIBLE_SDK_VERSION, /// - /// The given area file does not exist, check the path + /// The given area file does not exist. Check the file path. /// INVALID_AREA_FILE, /// - /// The area file does not contain enought data to be used or the sl::DEPTH_MODE used during the creation of the area file is different from the one currently set. + /// The area file does not contain enough data to be used ,or the sl::DEPTH_MODE used during the creation of the + /// area file is different from the one currently set. /// INCOMPATIBLE_AREA_FILE, /// - /// Camera failed to setup + /// Camera failed to set up. /// CAMERA_FAILED_TO_SETUP, /// - /// Your ZED can not be opened, try replugging it to another USB port or flipping the USB-C connector + /// Your ZED cannot be opened. Try replugging it to another USB port or flipping the USB-C connector (if using ZED Mini). /// CAMERA_DETECTION_ISSUE, /// - /// The Camera is already used by another process + /// The Camera is already in use by another process. /// CAMERA_ALREADY_IN_USE, /// - /// No GPU found, CUDA is unable to list it. Can be a driver/reboot issue + /// No GPU found or CUDA is unable to list it. Can be a driver/reboot issue. /// NO_GPU_DETECTED, /// - /// Plane not found, either no plane is detected in the scene, at the location or corresponding to the floor, or the floor plane doesn't match the prior given + /// Plane not found. Either no plane is detected in the scene, at the location or corresponding to the floor, + /// or the floor plane doesn't match the prior given. /// ERROR_CODE_PLANE_NOT_FOUND, /// - /// end of error code (used before init) + /// End of error code. Used before init has been called. /// ERROR_CODE_LAST }; /// - /// Represents the available resolution + /// Represents the available resolution options. /// public enum RESOLUTION { /// - /// 2208*1242, supported frame rate : 15 fps + /// 2208*1242. Supported frame rate: 15 FPS. /// HD2K, /// - /// 1920*1080, supported frame rates : 15, 30 fps + /// 1920*1080. Supported frame rates: 15, 30 FPS. /// HD1080, /// - /// 1280*720, supported frame rates : 15, 30, 60 fps + /// 1280*720. Supported frame rates: 15, 30, 60 FPS. /// HD720, /// - /// 672*376, supported frame rates : 15, 30, 60, 100 fps + /// 672*376. Supported frame rates: 15, 30, 60, 100 FPS. /// VGA }; /// - /// List available depth sensing modes. + /// Types of compatible ZED cameras. /// public enum MODEL { - ZED, /**< ZED camera.*/ - ZED_M /**< ZED M device.*/ + /// + /// Original ZED camera. + /// + ZED, + /// + /// ZED Mini. + /// + ZED_M }; /// - /// List available depth sensing modes. + /// Lists available sensing modes - whether to produce the original depth map (STANDARD) or one with + /// smoothing and other effects added to fill gaps and roughness (FILL). /// public enum SENSING_MODE { /// - /// This mode outputs ZED standard depth map that preserves edges and depth accuracy. - /// Applications example: Obstacle detection, Automated navigation, People detection, 3D reconstruction + /// This mode outputs the standard ZED depth map that preserves edges and depth accuracy. + /// However, there will be missing data where a depth measurement couldn't be taken, such as from + /// a surface being occluded from one sensor but not the other. + /// Better for: Obstacle detection, autonomous navigation, people detection, 3D reconstruction. /// STANDARD, /// - /// This mode outputs a smooth and fully dense depth map. - /// Applications example: AR/VR, Mixed-reality capture, Image post-processing + /// This mode outputs a smooth and fully dense depth map. It doesn't have gaps in the data + /// like STANDARD where depth can't be calculated directly, but the values it fills them with + /// is less accurate than a real measurement. + /// Better for: AR/VR, mixed-reality capture, image post-processing. /// FILL }; /// - /// List available views. - /// + /// Lists available view types retrieved from the camera, used for creating human-viewable (Image-type) textures. + /// + /// Based on the VIEW enum in the ZED C++ SDK. For more info, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/group__Video__group.html#ga77fc7bfc159040a1e2ffb074a8ad248c + /// public enum VIEW { /// - /// Left RGBA image, sl::MAT_TYPE_8U_C4. + /// Left RGBA image. As a ZEDMat, MAT_TYPE is set to MAT_TYPE_8U_C4. /// LEFT, /// - /// Right RGBA image, sl::MAT_TYPE_8U_C4. + /// Right RGBA image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. /// RIGHT, /// - /// Left GRAY image, sl::MAT_TYPE_8U_C1. + /// Left GRAY image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. /// LEFT_GREY, /// - /// Right GRAY image, sl::MAT_TYPE_8U_C1. + /// Right GRAY image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. /// RIGHT_GREY, /// - /// Left RGBA unrectified image, sl::MAT_TYPE_8U_C4. + /// Left RGBA unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. /// LEFT_UNRECTIFIED, /// - /// Right RGBA unrectified image, sl::MAT_TYPE_8U_C4. + /// Right RGBA unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. /// RIGHT_UNRECTIFIED, /// - /// Left GRAY unrectified image, sl::MAT_TYPE_8U_C1. + /// Left GRAY unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. /// LEFT_UNRECTIFIED_GREY, /// - /// Right GRAY unrectified image, sl::MAT_TYPE_8U_C1. + /// Right GRAY unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. /// RIGHT_UNRECTIFIED_GREY, /// - /// Left and right image (the image width is therefore doubled) RGBA image, MAT_8U_C4. + /// Left and right image. Will be double the width to hold both. As a ZEDMat, MAT_TYPE is set to MAT_8U_C4. /// SIDE_BY_SIDE, /// - /// Normalized depth image + /// Normalized depth image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. + /// Use an Image texture for viewing only. For measurements, use a Measure type instead + /// (ZEDCamera.RetrieveMeasure()) to preserve accuracy. /// DEPTH, /// - /// Normalized confidence image, MAT_8U_C4. + /// Normalized confidence image. As a ZEDMat, MAT_TYPE is set to MAT_8U_C4. + /// Use an Image texture for viewing only. For measurements, use a Measure type instead + /// (ZEDCamera.RetrieveMeasure()) to preserve accuracy. /// CONFIDENCE, /// - /// Color rendering of the normals, MAT_8U_C4. + /// Color rendering of the normals. As a ZEDMat, MAT_TYPE is set to MAT_8U_C4. + /// Use an Image texture for viewing only. For measurements, use a Measure type instead + /// (ZEDCamera.RetrieveMeasure()) to preserve accuracy. /// NORMALS, /// - /// Color rendering of the right depth mapped on right sensor, MAT_8U_C4. + /// Color rendering of the right depth mapped on right sensor. As a ZEDMat, MAT_TYPE is set to MAT_8U_C4. + /// Use an Image texture for viewing only. For measurements, use a Measure type instead + /// (ZEDCamera.RetrieveMeasure()) to preserve accuracy. /// DEPTH_RIGHT, /// - /// Color rendering of the normals mapped on right sensor, MAT_8U_C4. + /// Color rendering of the normals mapped on right sensor. As a ZEDMat, MAT_TYPE is set to MAT_8U_C4. + /// Use an Image texture for viewing only. For measurements, use a Measure type instead + /// (ZEDCamera.RetrieveMeasure()) to preserve accuracy. /// NORMALS_RIGHT }; /// - /// List available camera settings for the ZED camera (contrast, hue, saturation, gain...). + /// Lists available camera settings for the ZED camera (contrast, hue, saturation, gain, etc.) /// public enum CAMERA_SETTINGS { /// - /// Defines the brightness control. Affected value should be between 0 and 8 + /// Brightness control. Value should be between 0 and 8. /// BRIGHTNESS, /// - /// Defines the contrast control. Affected value should be between 0 and 8 + /// Contrast control. Value should be between 0 and 8. /// CONTRAST, /// - /// Defines the hue control. Affected value should be between 0 and 11 + /// Hue control. Value should be between 0 and 11. /// HUE, /// - /// Defines the saturation control. Affected value should be between 0 and 8 + /// Saturation control. Value should be between 0 and 8 /// SATURATION, /// - /// Defines the gain control. Affected value should be between 0 and 100 for manual control. If ZED_EXPOSURE is set to -1, the gain is in auto mode too. + /// Gain control. Value should be between 0 and 100 for manual control. + /// If ZED_EXPOSURE is set to -1 (automatic mode), then gain will be automatic as well. /// GAIN, /// - /// Defines the exposure control. A -1 value enable the AutoExposure/AutoGain control. Affected value should be between 0 and 100 for manual control. A 0 value only disable auto mode without modifing the last auto values, while a 1 to 100 value disable auto mode and set exposure to chosen value + /// Exposure control. Value can be between 0 and 100. + /// Setting to -1 enables auto exposure and auto gain. + /// Setting to 0 disables auto exposure but doesn't change the last applied automatic values. + /// Setting to 1-100 disables auto mode and sets exposure to the chosen value. /// EXPOSURE, /// - /// Defines the color temperature control. Affected value should be between 2800 and 6500 with a step of 100. A value of -1 set the AWB ( auto white balance), as the boolean parameter (default) does. + /// Color temperature control. Value should be between 2800 and 6500 with a step of 100. + /// Setting to -1 enables AWB (automatic white balance). /// WHITEBALANCE }; /// - /// List retrievable measures. + /// Lists available measure types retrieved from the camera, used for creating precise measurement maps + /// (Measure-type textures). + /// Based on the MEASURE enum in the ZED C++ SDK. For more info, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/group__Depth__group.html#ga798a8eed10c573d759ef7e5a5bcd545d /// public enum MEASURE { /// - /// Disparity map, 1 channel, FLOAT + /// Disparity map. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. /// DISPARITY, /// - /// Depth map, 1 channel, FLOAT + /// Depth map. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. /// DEPTH, /// - /// Certainty/confidence of the disparity map, 1 channel, FLOAT + /// Certainty/confidence of the disparity map. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. /// CONFIDENCE, /// - /// 3D coordinates of the image points, 4 channels, FLOAT (the 4th channel may contains the colors) + /// 3D coordinates of the image points. Used for point clouds in ZEDPointCloudManager. + /// As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. The 4th channel may contain the colors. /// XYZ, /// - /// 3D coordinates and Color of the image , 4 channels, FLOAT (the 4th channel encode 4 UCHAR for color in R-G-B-A order) + /// 3D coordinates and color of the image. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// The 4th channel encodes 4 UCHARs for colors in R-G-B-A order. /// XYZRGBA, /// - /// 3D coordinates and Color of the image , 4 channels, FLOAT (the 4th channel encode 4 UCHAR for color in B-G-R-A order) + /// 3D coordinates and color of the image. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// The 4th channel encode 4 UCHARs for colors in B-G-R-A order. /// XYZBGRA, /// - /// 3D coordinates and Color of the image , 4 channels, FLOAT (the 4th channel encode 4 UCHAR for color in A-R-G-B order) + /// 3D coordinates and color of the image. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// The 4th channel encodes 4 UCHARs for color in A-R-G-B order. /// XYZARGB, /// - /// 3D coordinates and Color of the image, 4 channels, FLOAT, channel 4 contains color in A-B-G-R order. + /// 3D coordinates and color of the image. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 contains color in A-B-G-R order. /// XYZABGR, /// - /// 3D coordinates and Color of the image , 4 channels, FLOAT (the 4th channel encode 4 UCHAR for color in A-B-G-R order) + /// 3D coordinates and color of the image. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// The 4th channel encode 4 UCHARs for color in A-B-G-R order. /// NORMALS, /// - /// Disparity map for right sensor, 1 channel, FLOAT. + /// Disparity map for the right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. /// DISPARITY_RIGHT, /// - /// Depth map for right sensor, 1 channel, FLOAT. + /// Depth map for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. /// DEPTH_RIGHT, /// - /// Point cloud for right sensor, 4 channels, FLOAT, channel 4 is empty. + /// Point cloud for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. Channel 4 is empty. /// XYZ_RIGHT, /// - /// Colored point cloud for right sensor, 4 channels, FLOAT, channel 4 contains color in R-G-B-A order. + /// Colored point cloud for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 contains colors in R-G-B-A order. /// XYZRGBA_RIGHT, /// - /// Colored point cloud for right sensor, 4 channels, FLOAT, channel 4 contains color in B-G-R-A order. + /// Colored point cloud for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 contains colors in B-G-R-A order. /// XYZBGRA_RIGHT, /// - /// Colored point cloud for right sensor, 4 channels, FLOAT, channel 4 contains color in A-R-G-B order. + /// Colored point cloud for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 contains colors in A-R-G-B order. /// XYZARGB_RIGHT, /// - /// Colored point cloud for right sensor, 4 channels, FLOAT, channel 4 contains color in A-B-G-R order. + /// Colored point cloud for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 contains colors in A-B-G-R order. /// XYZABGR_RIGHT, /// - /// Normals vector for right view, 4 channels, FLOAT, channel 4 is empty (set to 0) + /// Normals vector for right view. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 is empty (set to 0). /// NORMALS_RIGHT @@ -567,75 +681,76 @@ public enum MEASURE /// - /// Only few functions of tracking use this system, the path is the default value + /// Categories indicating when a timestamp is captured. /// public enum TIME_REFERENCE { /// - /// time when the image was captured on the USB + /// Timestamp from when the image was received over USB from the camera, defined + /// by when the entire image was available in memory. /// IMAGE, /// - /// current time (time of the function call) + /// Timestamp from when the relevant function was called. /// CURRENT }; /// - /// Reference frame (world or camera) for the tracking and depth sensing + /// Reference frame (world or camera) for tracking and depth sensing. /// public enum REFERENCE_FRAME { /// - /// The matrix contains the displacement from the first camera to the current one + /// Matrix contains the total displacement from the world origin/the first tracked point. /// WORLD, /// - /// The matrix contains the displacement from the previous camera position to the current one + /// Matrix contains the displacement from the previous camera position to the current one. /// CAMERA }; /// - /// List the different states of positional tracking. + /// Possible states of the ZED's Tracking system. /// public enum TRACKING_STATE { /// - /// The tracking is searching a match from the database to relocate at a previously known position + /// Tracking is searching for a match from the database to relocate to a previously known position. /// TRACKING_SEARCH, /// - /// The tracking operates normally, the path should be correct + /// Tracking is operating normally; tracking data should be correct. /// TRACKING_OK, /// - /// The tracking is not enabled + /// Tracking is not enabled. /// TRACKING_OFF } /// - /// List of svo compressions mode available + /// SVO compression modes. /// public enum SVO_COMPRESSION_MODE { /// - /// RAW images, no compression + /// RAW images; no compression. This option can lead to extremely large file sizes. /// RAW_BASED, /// - /// new Lossless, with png/zstd based compression : avg size = 42% of RAW + /// Lossless compression based on png/zstd. Average size = 42% of RAW. /// LOSSLESS_BASED, /// - /// new Lossy, with jpeg based compression : avg size = 22% of RAW + /// Lossy compression based on jpeg. Average size = 22% of RAW. /// LOSSY_BASED } /// - /// List of mesh format available + /// Mesh formats that can be saved/loaded with spatial mapping. /// public enum MESH_FILE_FORMAT { @@ -648,13 +763,13 @@ public enum MESH_FILE_FORMAT /// BIN, /// - /// Contains vertices, normals, faces and textures informations if possible. + /// Contains vertices, normals, faces, and texture information (if possible). /// OBJ } /// - /// List of filters avvailable for the spatial mapping + /// Presets for filtering meshes scannedw ith spatial mapping. Higher values reduce total face count by more. /// public enum FILTER { @@ -667,26 +782,26 @@ public enum FILTER /// MEDIUM, /// - /// Drasticly reduce the number of faces. + /// Drastically reduce the number of faces. /// HIGH, } /// - /// List of spatial mapping state + /// Possible states of the ZED's Spatial Mapping system. /// public enum SPATIAL_MAPPING_STATE { /// - /// The spatial mapping is initializing. + /// Spatial mapping is initializing. /// SPATIAL_MAPPING_STATE_INITIALIZING, /// - /// The depth and tracking data were correctly integrated in the fusion algorithm. + /// Depth and tracking data were correctly integrated into the fusion algorithm. /// SPATIAL_MAPPING_STATE_OK, /// - /// The maximum memory dedicated to the scanning has been reach, the mesh will no longer be updated. + /// Maximum memory dedicated to scanning has been reached; the mesh will no longer be updated. /// SPATIAL_MAPPING_STATE_NOT_ENOUGH_MEMORY, /// @@ -694,113 +809,127 @@ public enum SPATIAL_MAPPING_STATE /// SPATIAL_MAPPING_STATE_NOT_ENABLED, /// - /// Effective FPS is too low to give proper results for spatial mapping. Consider using PERFORMANCES parameters (DEPTH_MODE_PERFORMANCE, low camera resolution (VGA,HD720), spatial mapping low resolution) + /// Effective FPS is too low to give proper results for spatial mapping. + /// Consider using performance-friendly parameters (DEPTH_MODE_PERFORMANCE, VGA or HD720 camera resolution, + /// and LOW spatial mapping resolution). /// SPATIAL_MAPPING_STATE_FPS_TOO_LOW } /// - /// Unit used by the SDK. Prefer using METER with Unity + /// Units used by the SDK for measurements and tracking. METER is best to stay consistent with Unity. /// public enum UNIT { /// - /// International System, 1/1000 METER. + /// International System, 1/1000 meters. /// MILLIMETER, /// - /// International System, 1/100 METER. + /// International System, 1/100 meters. /// CENTIMETER, /// - /// International System, 1METER. + /// International System, 1/1 meters. /// METER, /// - /// Imperial Unit, 1/12 FOOT + /// Imperial Unit, 1/12 feet. /// INCH, /// - /// Imperial Unit, 1 FOOT + /// Imperial Unit, 1/1 feet. /// FOOT } /// - /// Parameters that will be fixed for the whole execution life time of the camera. + /// Struct containing all parameters passed to the SDK when initializing the ZED. + /// These parameters will be fixed for the whole execution life time of the camera. + /// For more details, see the InitParameters class in the SDK API documentation: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/structsl_1_1InitParameters.html /// public class InitParameters { /// - /// Define the chosen ZED resolution + /// Resolution the ZED will be set to. /// public sl.RESOLUTION resolution; /// - /// Requested FPS for this resolution. set as 0 will choose the default FPS for this resolution (see User guide). + /// Requested FPS for this resolution. Setting it to 0 will choose the default FPS for this resolution. /// public int cameraFPS; /// - /// ONLY for LINUX : if multiple ZEDs are connected. Is not used in Unity + /// ID for identifying which of multiple connected ZEDs to use. + /// NOT CURRENTLY SUPPORTED IN UNITY. /// public int cameraLinuxID; /// - /// Path with filename to the recorded SVO file. + /// Path to a recorded SVO file to play, including filename. /// public string pathSVO = ""; /// - /// This mode simulates the live camera and consequently skipped frames if the computation framerate is too slow. + /// In SVO playback, this mode simulates a live camera and consequently skipped frames if the computation framerate is too slow. /// public bool svoRealTimeMode; /// - /// Define the unit for all the metric values ( depth, point cloud, tracking, mesh). + /// Define a unit for all metric values (depth, point clouds, tracking, meshes, etc.) Meters are recommended for Unity. /// public UNIT coordinateUnit; /// - /// This defines the order and the direction of the axis of the coordinate system. see COORDINATE_SYSTEM for more information. + /// This defines the order and the direction of the axis of the coordinate system. + /// LEFT_HANDED_Y_UP is recommended to match Unity's coordinates. /// public COORDINATE_SYSTEM coordinateSystem; /// - /// Defines the quality of the depth map, affects the level of details and also the computation time. + /// Quality level of depth calculations. Higher settings improve accuracy but cost performance. /// public sl.DEPTH_MODE depthMode; /// - /// Specify the minimum depth value that will be computed, in the UNIT you define. + /// Minimum distance from the camera from which depth will be computed, in the defined coordinateUnit. /// public float depthMinimumDistance; /// - /// Defines if the image are horizontally flipped. + /// Defines if images are horizontally flipped. /// public bool cameraImageFlip; /// - /// Defines if right MEASURE should be computed (needed for MEASURE__RIGHT) + /// Defines if measures relative to the right sensor should be computed (needed for MEASURE__RIGHT). /// public bool enableRightSideMeasure; /// - /// If set to true, it will disable self-calibration and take the optional calibration parameters without optimizing them. - /// It is advised to leave it as false, so that calibration parameters can be optimized. + /// True to disable self-calibration and use the optional calibration parameters without optimizing them. + /// False is recommended, so that calibration parameters can be optimized. /// public bool cameraDisableSelfCalib; /// - /// ONLY for LINUX : Set the number of buffers in the internal grabbing process. DO NOT WORK ON UNITY + /// Set the number of buffers for the internal buffer process. LINUX ONLY - NOT CURRENTLY USED IN UNITY PLUGIN. /// public int cameraBufferCountLinux; /// - /// Defines if you want the SDK provides text feedback. + /// True for the SDK to provide text feedback. /// public bool sdkVerbose; /// - /// Defines the graphics card on which the computation will be done. + /// ID of the graphics card on which the ZED's computations will be performed. /// public int sdkGPUId; /// - /// Store the program outputs into the log file defined by its filename. + /// If set to verbose, the filename of the log file into which the SDK will store its text output. /// public string sdkVerboseLogFile = ""; /// - /// Defines if the depth map should be stabilize. + /// True to stabilize the depth map. Recommended. /// public bool depthStabilization; + /// + /// Optional path for searching configuration (calibration) file SNxxxx.conf. (introduced in ZED SDK 2.6) + /// + public string optionalSettingsPath = ""; + /// + /// Constructor. Sets default initialization parameters recommended for Unity. + /// public InitParameters() { this.resolution = RESOLUTION.HD720; @@ -820,20 +949,23 @@ public InitParameters() this.sdkVerboseLogFile = ""; this.enableRightSideMeasure = false; this.depthStabilization = true; + this.optionalSettingsPath = ""; } } /// - /// List of available system of coordinates + /// List of available coordinate systems. Left-Handed, Y Up is recommended to stay consistent with Unity. + /// consistent with Unity. /// public enum COORDINATE_SYSTEM { /// - /// Standard coordinates system in computer vision. Used in OpenCV : see here : http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html + /// Standard coordinates system used in computer vision. + /// Used in OpenCV. See: http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html /// IMAGE, /// - /// Left-Handed with Y up and Z forward. Used in Unity with DirectX + /// Left-Handed with Y up and Z forward. Recommended. Used in Unity with DirectX. /// LEFT_HANDED_Y_UP, /// @@ -851,99 +983,115 @@ public enum COORDINATE_SYSTEM } /// - /// List the different states of spatial memory area export. + /// Possible states of the ZED's spatial memory area export, for saving 3D features used + /// by the tracking system to relocalize the camera. This is used when saving a mesh generated + /// by spatial mapping when Save Mesh is enabled - a .area file is saved as well. /// public enum AREA_EXPORT_STATE { /// - /// The spatial memory file has been successfully created. + /// Spatial memory file has been successfully created. /// AREA_EXPORT_STATE_SUCCESS, /// - /// The spatial memory is currently written. + /// Spatial memory file is currently being written to. /// AREA_EXPORT_STATE_RUNNING, /// - /// The spatial memory file exportation has not been called. + /// Spatial memory file export has not been called. /// AREA_EXPORT_STATE_NOT_STARTED, /// - /// The spatial memory contains no data, the file is empty. + /// Spatial memory contains no data; the file is empty. /// AREA_EXPORT_STATE_FILE_EMPTY, /// - /// The spatial memory file has not been written because of a wrong file name. + /// Spatial memory file has not been written to because of a bad file name. /// AREA_EXPORT_STATE_FILE_ERROR, /// - /// The spatial memory learning is disable, no file can be created. + /// Spatial memory has been disabled, so no file can be created. /// AREA_EXPORT_STATE_SPATIAL_MEMORY_DISABLED }; /// - /// Runtime parameters used by the grab + /// Runtime parameters used by the ZEDCamera.Grab() function, and its Camera::grab() counterpart in the SDK. /// [StructLayout(LayoutKind.Explicit)] public struct RuntimeParameters { /// - /// Defines the algorithm used for depth map computation, more info : \ref SENSING_MODE definition. + /// Defines the algorithm used for depth map computation, more info : \ref SENSING_MODE definition. /// - [FieldOffset(12)]//In 2.2 the runtime parameters needs 3 int of offset + [FieldOffset(12)] //In 2.2, the runtime parameters need 3 int of offset. public sl.SENSING_MODE sensingMode; /// - /// Provides 3D measures (point cloud and normals) in the desired reference frame (default is REFERENCE_FRAME_CAMERA) + /// Provides 3D measures (point cloud and normals) in the desired reference frame (default is REFERENCE_FRAME_CAMERA). /// [FieldOffset(16)] public sl.REFERENCE_FRAME measure3DReferenceFrame; /// - /// Defines if the depth map should be computed. + /// Defines whether the depth map should be computed. /// [MarshalAs(UnmanagedType.U1)] [FieldOffset(20)] public bool enableDepth; /// - /// Defines if the point cloud should be computed (including XYZRGBA). + /// Defines whether the point cloud should be computed (including XYZRGBA). /// [MarshalAs(UnmanagedType.U1)] [FieldOffset(21)] public bool enablePointCloud; - } /// - /// Tracking Frame choices : Left (left sensor), Center (Center of the camera), Right (right sensor) + /// Part of the ZED (left/right sensor, center) that's considered its center for tracking purposes. /// public enum TRACKING_FRAME { + /// + /// Camera's center is at the left sensor. + /// LEFT_EYE, + /// + /// Camera's center is in the camera's physical center, between the sensors. + /// CENTER_EYE, + /// + /// Camera's center is at the right sensor. + /// RIGHT_EYE }; /// - /// List of specific usb device + /// Types of USB device brands. /// - public enum USB_DEVICE { + public enum USB_DEVICE + { + /// + /// Oculus device, eg. Oculus Rift VR Headset. + /// USB_DEVICE_OCULUS, + /// + /// HTC device, eg. HTC Vive. + /// USB_DEVICE_HTC, + /// + /// Stereolabs device, eg. ZED/ZED Mini. + /// USB_DEVICE_STEREOLABS }; /// - /// Constant Rendering Plane distance (Don't change this) + /// Constant for the distance of the rendering planes from the camera. Don't change this. /// - public enum Constant { + public enum Constant + { PLANE_DISTANCE = 10 }; - - - - - }// end namespace sl diff --git a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDMat.cs b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDMat.cs index 86bc8732..eaa5bb19 100644 --- a/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDMat.cs +++ b/ZEDCamera/Assets/ZED/SDK/NativeInterface/ZEDMat.cs @@ -1,18 +1,27 @@ //======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== -//Wrapper to the Mat of the ZED using System; using System.Runtime.InteropServices; +/// +/// This file holds the ZEDMat class along with low-level structures used for passing data between +/// the C# ZEDMat and its equivalent in the SDK. +/// namespace sl { - + /// + /// Represents a 2D vector of uchars for use on both the CPU and GPU. + /// [StructLayout(LayoutKind.Sequential)] public struct char2 { public byte r; public byte g; } + + /// + /// Represents a 3D vector of uchars for use on both the CPU and GPU. + /// [StructLayout(LayoutKind.Sequential)] public struct char3 { @@ -20,6 +29,10 @@ public struct char3 public byte g; public byte b; } + + /// + /// Represents a 4D vector of uchars for use on both the CPU and GPU. + /// [StructLayout(LayoutKind.Sequential)] public struct char4 { @@ -32,12 +45,19 @@ public struct char4 [MarshalAs(UnmanagedType.U1)] public byte a; } + + /// + /// Represents a 2D vector of floats for use on both the CPU and GPU. + /// [StructLayout(LayoutKind.Sequential)] public struct float2 { public float r; public float g; } + /// + /// Represents a 3D vector of floats for use on both the CPU and GPU. + /// [StructLayout(LayoutKind.Sequential)] public struct float3 { @@ -45,6 +65,9 @@ public struct float3 public float g; public float b; } + /// + /// Represents a 4D vector of floats for use on both the CPU and GPU. + /// [StructLayout(LayoutKind.Sequential)] public struct float4 { @@ -54,33 +77,95 @@ public struct float4 public float a; } + /// + /// Mirrors the sl::Mat class used in the ZED C++ SDK to store images. + /// Can be used to retrieve individual images from GPU or CPU memory: see ZEDCamera.RetrieveImage() + /// and ZEDCamera.RetrieveMeasure(). + /// + /// For more information on the Mat class it mirrors, see: + /// https://www.stereolabs.com/developers/documentation/API/v2.5.1/classsl_1_1Mat.html + /// public class ZEDMat { + /// + /// Type of mat, indicating the data type and the number of channels it holds. + /// Proper mat type depends on the image type. See sl.VIEW and sl.MEASURE (in ZEDCommon.cs) + /// public enum MAT_TYPE { - MAT_32F_C1, /*!< float 1 channel.*/ - MAT_32F_C2, /*!< float 2 channels.*/ + /// + /// Float, one channel. Used for depth and disparity Measure-type textures. + /// + MAT_32F_C1, + /// + /// Float, two channels. + /// + MAT_32F_C2, + /// + /// Float, three channels. + /// MAT_32F_C3, /*!< float 3 channels.*/ - MAT_32F_C4, /*!< float 4 channels.*/ - MAT_8U_C1, /*!< unsigned char 1 channel.*/ - MAT_8U_C2, /*!< unsigned char 2 channels.*/ - MAT_8U_C3, /*!< unsigned char 3 channels.*/ - MAT_8U_C4 /*!< unsigned char 4 channels.*/ + /// + /// Float, four channels. Used for normals and XYZ (point cloud) measure-type textures + /// + MAT_32F_C4, + /// + /// Unsigned char, one channel. Used for greyscale image-type textures like depth and confidence displays. + /// + MAT_8U_C1, + /// + /// Unsigned char, two channels. + /// + MAT_8U_C2, + /// + /// Unsigned char, three channels. + /// + MAT_8U_C3, + /// + /// Unsigned char, four channels. Used for color images, like the main RGB image from each sensor. + /// + MAT_8U_C4 }; + /// + /// Categories for copying data within or between the CPU (processor) memory and GPU (graphics card) memory. + /// public enum COPY_TYPE { + /// + /// Copies data from one place in CPU memory to another. + /// COPY_TYPE_CPU_CPU, /*!< copy data from CPU to CPU.*/ + /// + /// Copies data from CPU memory to GPU memory. + /// COPY_TYPE_CPU_GPU, /*!< copy data from CPU to GPU.*/ + /// + /// Copies data from one place in GPU memory to another. + /// COPY_TYPE_GPU_GPU, /*!< copy data from GPU to GPU.*/ + /// + /// Copies data from GPU memory to CPU memory. + /// COPY_TYPE_GPU_CPU /*!< copy data from GPU to CPU.*/ }; + /// + /// Which memory to store an image/mat: CPU/processor memory or GPU (graphics card) memory. + /// public enum MEM { - MEM_CPU = 1, /*!< CPU Memory (Processor side).*/ - MEM_GPU = 2 /*!< GPU Memory (Graphic card side).*/ + /// + /// Store on memory accessible by the CPU. + /// + MEM_CPU = 1, + /// + /// Store on memory accessible by the GPU. + /// + MEM_GPU = 2 }; + + #region DLL Calls const string nameDll = "sl_unitywrapper"; [DllImport(nameDll, EntryPoint = "dllz_mat_create_new")] @@ -212,10 +297,14 @@ public enum MEM [DllImport(nameDll, EntryPoint = "dllz_mat_clone")] private static extern void dllz_mat_clone(System.IntPtr ptr, System.IntPtr ptrSource); - private System.IntPtr _matInternalPtr; + #endregion /// - /// Returns the internal ptr of a mat + /// Returns the internal ptr of a Mat. + /// + private System.IntPtr _matInternalPtr; + /// + /// Returns the internal ptr of a Mat. /// public IntPtr MatPtr { @@ -223,7 +312,7 @@ public IntPtr MatPtr } /// - /// Creates an empty mat + /// Creates an empty Mat. /// public ZEDMat() { @@ -231,43 +320,47 @@ public ZEDMat() } /// - /// Creates a mat from + /// Creates a mat from an existing internal ptr. /// - /// + /// IntPtr to create the material with. public ZEDMat(System.IntPtr ptr) { if(ptr == IntPtr.Zero) { - throw new Exception("ZED Mat not initialized"); + throw new Exception("ZED Mat not initialized."); } _matInternalPtr = ptr; } /// - /// Creates a Mat with a resolution + /// Creates a Mat with a given resolution. /// - /// - /// - /// + /// Resolution for the new Mat. + /// Data type and number of channels the Mat will hold. + /// Depends on texture type: see sl.VIEW and sl.MEASURE in ZEDCommon.cs. + /// Whether Mat should exist on CPU or GPU memory. + /// Choose depending on where you'll need to access it from. public ZEDMat(sl.Resolution resolution, MAT_TYPE type, MEM mem = MEM.MEM_CPU) { _matInternalPtr = dllz_mat_create_new(resolution, (int)(type), (int)(mem)); } /// - /// Creates a Mat + /// Creates a Mat with a given width and height. /// - /// - /// - /// - /// + /// Width of the new Mat. + /// Height of the new Mat. + /// Data type and number of channels the Mat will hold. + /// Depends on texture type: see sl.VIEW and sl.MEASURE in ZEDCommon.cs. + /// Whether Mat should exist on CPU or GPU memory. + /// Choose depending on where you'll need to access it from. public ZEDMat(uint width, uint height, MAT_TYPE type, MEM mem = MEM.MEM_CPU) { _matInternalPtr = dllz_mat_create_new(new sl.Resolution(width, height), (int)(type), (int)(mem)); } /// - /// Defines whether the Mat is initialized or not. + /// True if the Mat has been initialized. /// /// public bool IsInit() @@ -276,9 +369,9 @@ public bool IsInit() } /// - /// Free the memory of the Mat + /// Frees the memory of the Mat. /// - /// + /// Whether the Mat is on CPU or GPU memory. public void Free(MEM mem = (MEM.MEM_GPU | MEM.MEM_CPU)) { dllz_mat_free(_matInternalPtr, (int)mem); @@ -286,7 +379,7 @@ public void Free(MEM mem = (MEM.MEM_GPU | MEM.MEM_CPU)) } /// - /// Downloads data from DEVICE (GPU) to HOST (CPU), if possible. + /// Copies data from the GPU to the CPU, if possible. /// /// public sl.ERROR_CODE UpdateCPUFromGPU() @@ -295,7 +388,7 @@ public sl.ERROR_CODE UpdateCPUFromGPU() } /// - /// Uploads data from HOST (CPU) to DEVICE (GPU), if possible. + /// Copies data from the CPU to the GPU, if possible. /// /// public sl.ERROR_CODE UpdateGPUFromCPU() @@ -304,9 +397,9 @@ public sl.ERROR_CODE UpdateGPUFromCPU() } /// - /// Return the informations about the Mat + /// Returns information about the Mat. /// - /// + /// String providing Mat information. public string GetInfos() { byte[] buf = new byte[300]; @@ -315,31 +408,31 @@ public string GetInfos() } /// - /// Copies data an other Mat (deep copy). + /// Copies data from this Mat to another Mat (deep copy). /// - /// dst : the Mat where the data will be copied. - /// cpyType : specify the memories that will be used for the copy. - /// + /// Mat that the data will be copied to. + /// The To and From memory types. + /// Error code indicating if the copy was successful, or why it wasn't. public sl.ERROR_CODE CopyTo(sl.ZEDMat dest, sl.ZEDMat.COPY_TYPE copyType = COPY_TYPE.COPY_TYPE_CPU_CPU) { return (sl.ERROR_CODE)dllz_mat_copy_to(_matInternalPtr, dest._matInternalPtr, (int)(copyType)); } - + /// - /// Reads an image from a file (only if \ref MEM_CPU is available on the current + /// Reads an image from a file. Supports .png and .jpeg. Only works if Mat has access to MEM_CPU. /// - /// file path including the name and extension. - /// + /// File path, including file name and extension. + /// Error code indicating if the read was successful, or why it wasn't. public sl.ERROR_CODE Read(string filePath) { return (sl.ERROR_CODE)dllz_mat_read(_matInternalPtr, filePath); } /// - /// Writes the Mat (only if MEM_CPU is available) into a file as an image. + /// Writes the Mat into a file as an image. Only works if Mat has access to MEM_CPU. /// - /// file path including the name and extension. - /// + /// File path, including file name and extension. + /// Error code indicating if the write was successful, or why it wasn't. public sl.ERROR_CODE Write(string filePath) { return (sl.ERROR_CODE)dllz_mat_write(_matInternalPtr, filePath); @@ -364,9 +457,9 @@ public int GetHeight() } /// - /// Returns the number of values stored in one pixel. + /// Returns the number of values/channels stored in each pixel. /// - /// + /// Number of values/channels. public int GetChannels() { return dllz_mat_get_channels(_matInternalPtr); @@ -375,23 +468,23 @@ public int GetChannels() /// /// Returns the size in bytes of one pixel. /// - /// + /// Size in bytes. public int GetPixelBytes() { return dllz_mat_get_pixel_bytes(_matInternalPtr); } /// - /// Returns the memory step in number of elements (the number of values in one pixel row). + /// Returns the memory 'step' in number/length of elements - how many values make up each row of pixels. /// - /// + /// Step length. public int GetStep() { return dllz_mat_get_step(_matInternalPtr); } /// - /// Returns the memory step in Bytes (the Bytes size of one pixel row). + /// Returns the memory 'step' in bytes - how many bytes make up each row of pixels. /// /// public int GetStepBytes() @@ -400,7 +493,7 @@ public int GetStepBytes() } /// - /// Returns the size in bytes of a row. + /// Returns the size of each row in bytes. /// /// public int GetWidthBytes() @@ -418,7 +511,7 @@ public MEM GetMemoryType() } /// - /// Returns whether the Mat is the owner of the memory it access. + /// Returns whether the Mat is the owner of the memory it's accessing. /// /// public bool IsMemoryOwner() @@ -426,40 +519,44 @@ public bool IsMemoryOwner() return dllz_mat_is_memory_owner(_matInternalPtr); } + /// + /// Returns the resolution of the image that this Mat holds. + /// + /// public sl.Resolution GetResolution() { return dllz_mat_get_resolution(_matInternalPtr); } /// - /// Allocates the Mat memory. + /// Allocates memory for the Mat. /// - /// - /// - /// - /// + /// Width of the image/matrix in pixels. + /// Height of the image/matrix in pixels. + /// Type of matrix (data type and channels; see sl.MAT_TYPE) + /// Where the buffer will be stored - CPU memory or GPU memory. public void Alloc(uint width, uint height, MAT_TYPE matType, MEM mem = MEM.MEM_CPU) { dllz_mat_alloc(_matInternalPtr, (int)width, (int)height, (int)matType, (int)mem); } /// - /// Allocates the Mat memory. + /// Allocates memory for the Mat. /// - /// - /// - /// + /// Size of the image/matrix in pixels. + /// Type of matrix (data type and channels; see sl.MAT_TYPE) + /// Where the buffer will be stored - CPU memory or GPU memory. public void Alloc(sl.Resolution resolution, MAT_TYPE matType, MEM mem = MEM.MEM_CPU) { dllz_mat_alloc(_matInternalPtr, (int)resolution.width, (int)resolution.height, (int)matType, (int)mem); } /// - /// Copies data from an other Mat (deep copy). + /// Copies data from another Mat into this one(deep copy). /// - /// - /// - /// + /// Source Mat from which to copy. + /// The To and From memory types. + /// ERROR_CODE (as an int) indicating if the copy was successful, or why it wasn't. public int SetFrom(ZEDMat src, COPY_TYPE copyType = COPY_TYPE.COPY_TYPE_CPU_CPU) { return dllz_mat_set_from(_matInternalPtr, src._matInternalPtr, (int)copyType); @@ -471,7 +568,7 @@ public System.IntPtr GetPtr(MEM mem = MEM.MEM_CPU) } /// - /// Duplicates Mat by copy (deep copy). + /// Duplicates a Mat by copying all its data into a new one (deep copy). /// /// public void Clone(ZEDMat source) @@ -480,100 +577,100 @@ public void Clone(ZEDMat source) } /************ GET VALUES *********************/ - // Cannot send values by template, covariant issue with a out needed + //Cannot send values by template due to a covariant issue with an out needed. /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_32F_C1) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out float value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_float(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_32F_C2) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out float2 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_float2(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_32F_C3) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out float3 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_float3(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_32F_C4) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out float4 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_float4(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_TYPE_8U_C1) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out byte value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_uchar(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_TYPE_8U_C2) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out char2 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_uchar2(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_TYPE_8U_C3) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out char3 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_uchar3(_matInternalPtr, x, y, out value, (int)(mem))); } /// - /// Returns the value of a specific point in the matrix. + /// Returns the value of a specific point in the matrix. (MAT_TYPE_8U_C4) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Gets filled with the current value. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the get was successful, or why it wasn't. public sl.ERROR_CODE GetValue(int x, int y, out char4 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_get_value_uchar4(_matInternalPtr, x, y, out value, (int)(mem))); @@ -582,100 +679,100 @@ public sl.ERROR_CODE GetValue(int x, int y, out char4 value, sl.ZEDMat.MEM mem) /************ SET VALUES *********************/ - // Cannot send values by template, covariant issue with a out needed + //Cannot send values by template due to a covariant issue with an out needed. /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_32F_C1) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref float value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_float(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_32F_C2) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref float2 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_float2(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_32F_C3) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref float3 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_float3(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_32F_C4) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, float4 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_float4(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_TYPE_8U_C1) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref byte value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_uchar(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_TYPE_8U_C2) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref char2 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_uchar2(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_TYPE_8U_C3) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref char3 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_uchar3(_matInternalPtr, x, y, ref value, (int)(mem))); } /// - /// Sets a value to a specific point in the matrix. + /// Sets a value to a specific point in the matrix. (MAT_TYPE_8U_C4) /// - /// - /// - /// - /// - /// + /// Row the point is in. + /// Column the point is in. + /// Value to which the point will be set. + /// Whether point is on CPU memory or GPU memory. + /// Error code indicating if the set was successful, or why it wasn't. public sl.ERROR_CODE SetValue(int x, int y, ref char4 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_value_uchar4(_matInternalPtr, x, y, ref value, (int)(mem))); @@ -683,92 +780,91 @@ public sl.ERROR_CODE SetValue(int x, int y, ref char4 value, sl.ZEDMat.MEM mem) /***************************************************************************************/ /************ SET TO *********************/ - // Cannot send values by template, covariant issue with a out needed + //Cannot send values by template due to a covariant issue with an out needed. /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_32F_C1) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref float value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_float(_matInternalPtr, ref value, (int)(mem))); } - /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_32F_C2) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref float2 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_float2(_matInternalPtr, ref value, (int)(mem))); } /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_32F_C3) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref float3 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_float3(_matInternalPtr, ref value, (int)(mem))); } /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_32F_C4) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref float4 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_float4(_matInternalPtr, ref value, (int)(mem))); } /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_TYPE_8U_C1) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref byte value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_uchar(_matInternalPtr, ref value, (int)(mem))); } /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_TYPE_8U_C2) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref char2 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_uchar2(_matInternalPtr, ref value, (int)(mem))); } /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_TYPE_8U_C3) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo(ref char3 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_uchar3(_matInternalPtr, ref value, (int)(mem))); } /// - /// ills the Mat with the given value. + /// Fills the entire Mat with the given value. (MAT_TYPE_8U_C4) /// - /// - /// - /// + /// Value with which to fill the Mat. + /// Which buffer to fill - CPU or GPU memory. + /// Whether the set was successful, or why it wasn't. public sl.ERROR_CODE SetTo( ref char4 value, sl.ZEDMat.MEM mem) { return (sl.ERROR_CODE)(dllz_mat_set_to_uchar4(_matInternalPtr, ref value, (int)(mem))); diff --git a/ZEDCamera/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll b/ZEDCamera/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll index 7bc4eb4d..f952a2b7 100644 Binary files a/ZEDCamera/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll and b/ZEDCamera/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll differ